Django访问控制与IDOR审查Skill django-access-review

这个技能用于审查Django Web应用程序中的访问控制漏洞和IDOR(不安全的直接对象引用)安全问题。通过代码追踪和授权模型分析,帮助开发者和安全专家发现并修复权限漏洞,确保用户数据的安全隔离。关键词:Django、访问控制、IDOR、安全审查、授权、漏洞挖掘。

安全审计 0 次安装 0 次浏览 更新于 3/17/2026

name: django-access-review description: ‘Django访问控制和IDOR安全审查。在审查Django视图、DRF视图集、ORM查询或任何处理用户授权的Python/Django代码时使用。触发关键词:“IDOR”、“访问控制”、“授权”、“Django权限”、“对象权限”、“租户隔离”、“损坏访问”。’ allowed-tools: Read, Grep, Glob, Bash, Task license: LICENSE

<!– 参考材料基于OWASP Cheat Sheet Series (CC BY-SA 4.0) https://cheatsheetseries.owasp.org/ –>

Django访问控制与IDOR审查

通过调查代码库如何回答一个问题来查找访问控制漏洞:

用户A能否访问、修改或删除用户B的数据?

理念:调查而非模式匹配

不要扫描预定义的漏洞模式,而是:

  1. 理解授权在这个代码库中如何工作
  2. 提出问题关于具体的数据流
  3. 追踪代码以找到访问检查发生的位置(或是否发生)
  4. 报告仅通过调查确认的问题

每个代码库以不同方式实现授权。您的任务是理解这个具体实现,然后找到差距。


第一阶段:理解授权模型

在查找漏洞之前,回答以下关于代码库的问题:

授权是如何强制执行的?

研究代码库以找到:

□ 权限检查在哪里实现?
  - 装饰器? (@login_required, @permission_required, 自定义?)
  - 中间件? (TenantMiddleware, AuthorizationMiddleware?)
  - 基类? (BaseAPIView, TenantScopedViewSet?)
  - 权限类? (DRF permission_classes?)
  - 自定义混入? (OwnershipMixin, TenantMixin?)

□ 查询是如何作用域的?
  - 自定义管理器? (TenantManager, UserScopedManager?)
  - get_queryset() 重写?
  - 设置查询上下文的中间件?

□ 所有权模型是什么?
  - 单用户所有权? (document.owner_id)
  - 组织/租户所有权? (document.organization_id)
  - 分层? (org -> team -> user -> resource)
  - 上下文内的基于角色? (org admin vs member)

调查命令

# 查找典型授权方式
grep -rn "permission_classes\|@login_required\|@permission_required" --include="*.py" | head -20

# 查找视图继承的基类
grep -rn "class Base.*View\|class.*Mixin.*:" --include="*.py" | head -20

# 查找自定义管理器
grep -rn "class.*Manager\|def get_queryset" --include="*.py" | head -20

# 查找模型上的所有权字段
grep -rn "owner\|user_id\|organization\|tenant" --include="models.py" | head -30

在理解授权模型之前不要继续。


第二阶段:映射攻击面

识别处理用户特定数据的端点:

存在哪些资源?

□ 哪些模型包含用户数据?
□ 哪些拥有所有权字段 (owner_id, user_id, organization_id)?
□ 哪些通过URL或请求体中的ID访问?

暴露了哪些操作?

对于每个资源,映射:

  • 列表端点 - 返回什么数据?
  • 详情/检索端点 - 如何获取对象?
  • 创建端点 - 谁设置所有者?
  • 更新端点 - 用户能否修改他人的数据?
  • 删除端点 - 用户能否删除他人的数据?
  • 自定义操作 - 它们访问什么?

第三阶段:提问和调查

对于每个处理用户数据的端点,提问:

核心问题

“如果我是用户A,并且我知道用户B的资源的ID,我能访问它吗?”

追踪代码来回答:

1. 资源ID从哪里进入系统?
   - URL路径: /api/documents/{id}/
   - 查询参数: ?document_id=123
   - 请求体: {"document_id": 123}

2. 该ID在哪里用于获取数据?
   - 找到ORM查询或数据库调用

3. 在(1)和(2)之间,存在哪些检查?
   - 查询是否作用域到当前用户?
   - 是否有明确的所有权检查?
   - 是否有对象上的权限检查?
   - 基类或混入是否强制执行访问?

4. 如果找不到检查,是否错过了什么?
   - 检查父类
   - 检查中间件
   - 检查管理器
   - 检查URL级别的装饰器

后续问题

□ 对于列表端点:查询是否过滤到用户的数据,还是返回所有内容?

□ 对于创建端点:谁设置所有者 - 服务器还是请求?

□ 对于批量操作:它们是否作用域到用户的数据?

□ 对于相关资源:如果我能访问文档,我能访问其评论吗?
  如果文档属于其他人呢?

□ 对于租户/组织资源:组织A中的用户能否通过更改URL中的org_id来访问组织B的数据?

第四阶段:追踪具体流

选择一个具体端点并完全追踪。

示例调查

端点: GET /api/documents/{pk}/

1. 找到处理此URL的视图
   → DocumentViewSet.retrieve() 在 api/views.py

2. 检查DocumentViewSet继承自什么
   → class DocumentViewSet(viewsets.ModelViewSet)
   → 没有自定义基类进行授权

3. 检查permission_classes
   → permission_classes = [IsAuthenticated]
   → 仅检查登录,不检查所有权

4. 检查get_queryset()
   → def get_queryset(self):
   →     return Document.objects.all()
   → 返回所有文档!

5. 检查has_object_permission()
   → 未实现

6. 检查retrieve()方法
   → 使用默认,调用get_object()
   → get_object()使用get_queryset(),返回所有

7. 结论:IDOR - 任何经过身份验证的用户都可以访问任何文档

追踪时寻找什么

潜在差距指标(进一步调查,不要自动标记):
- get_queryset() 返回 .all() 或过滤时不包含用户
- 直接 Model.objects.get(pk=pk) 没有所有权在查询中
- ID来自请求体用于敏感操作
- 权限类检查认证但不检查所有权
- 没有has_object_permission()且queryset未作用域

可能安全的模式(但验证实现):
- get_queryset() 通过 request.user 或用户的组织过滤
- 自定义权限类带有 has_object_permission()
- 基类强制执行作用域
- 管理器自动过滤

第五阶段:报告发现

仅报告通过调查确认的问题。

置信度级别

级别 含义 行动
追踪了流,确认没有检查存在 报告并附证据
检查可能存在但无法确认 注意手动验证
理论性的,很可能已缓解 不报告

建议修复必须强制执行,而非文档化

错误修复:添加注释说“调用者必须验证权限” 正确修复:添加实际验证权限的代码

注释或文档字符串不强制执行授权。您的建议修复必须包含实际代码:

  • 验证用户在继续之前拥有权限
  • 如果未授权,引发异常或返回错误
  • 使未授权访问不可能,而不仅仅是劝阻

错误修复建议示例:

def get_resource(resource_id):
    # 重要:调用者必须确保用户有权访问此资源
    return Resource.objects.get(pk=resource_id)

正确修复建议示例:

def get_resource(resource_id, user):
    resource = Resource.objects.get(pk=resource_id)
    if resource.owner_id != user.id:
        raise PermissionDenied("访问被拒绝")
    return resource

如果您无法确定正确的执行机制,请说明 - 但绝不要建议文档作为修复。

报告格式

## 访问控制审查:[组件]

### 授权模型
[简要描述此代码库如何处理授权]

### 发现

#### [IDOR-001] [标题] (严重性:高/中)
- **位置**: `path/to/file.py:123`
- **置信度**: 高 - 通过代码追踪确认
- **问题**: 用户A能访问用户B的文档吗?
- **调查**:
  1. 追踪 GET /api/documents/{pk}/ 到 DocumentViewSet
  2. 检查 get_queryset() - 返回 Document.objects.all()
  3. 检查 permission_classes - 仅 IsAuthenticated
  4. 检查 has_object_permission() - 未实现
  5. 验证没有相关中间件或基类检查
- **证据**: [显示差距的代码片段]
- **影响**: 任何经过身份验证的用户都可以通过ID读取任何文档
- **建议修复**: [强制执行授权的代码 - 不是注释]

### 需要手动验证
[存在授权但无法确认有效性的问题]

### 未审查区域
[本审查未涵盖的端点或流]

常见的Django授权模式

这些是您可能找到的模式 - 不是要匹配的清单。

查询作用域

# 作用域到用户
Document.objects.filter(owner=request.user)

# 作用域到组织
Document.objects.filter(organization=request.user.organization)

# 使用自定义管理器
Document.objects.for_user(request.user)  # 调查这做什么

权限强制执行

# DRF权限类
permission_classes = [IsAuthenticated, IsOwner]

# 自定义 has_object_permission
def has_object_permission(self, request, view, obj):
    return obj.owner == request.user

# Django装饰器
@permission_required('app.view_document')

# 手动检查
if document.owner != request.user:
    raise PermissionDenied()

所有权分配

# 服务器端(安全)
def perform_create(self, serializer):
    serializer.save(owner=self.request.user)

# 从请求(调查)
serializer.save(**request.data)  # request.data是否包含owner?

调查清单

使用此指导您的审查,而不是通过/失败清单:

□ 我理解授权在此代码库中如何典型实现
□ 我已识别所有权模型(用户、组织、租户等)
□ 我已映射处理用户数据的关键端点
□ 对于每个敏感端点,我已追踪流并提问:
  - ID从哪里来?
  - 数据在哪里获取?
  - 在输入和数据访问之间有什么检查?
□ 我已通过检查父类和中间件验证了我的发现
□ 我仅报告了通过调查确认的问题