不安全的访问控制漏洞与防护
字数 1173 2025-11-07 22:15:37
不安全的访问控制漏洞与防护
描述
不安全的访问控制(Broken Access Control)指系统未能有效限制用户对资源或功能的访问权限,导致低权限用户可执行高权限操作(如普通用户访问管理员功能、越权查看他人数据等)。该漏洞在OWASP Top 10 2021中位列榜首,常见于垂直越权(权限提升)和水平越权(数据跨用户访问)。
核心问题
- 缺失权限验证:访问敏感功能或数据前未校验用户角色或权限。
- 依赖客户端校验:仅通过前端隐藏按钮或接口,但后端未做二次验证。
- 可预测的访问参数:通过修改URL中的ID(如
/user/123/profile)即可访问他人数据。
漏洞场景示例
假设有一个博客系统,用户可通过以下接口查看自己的文章:
GET /api/posts/12345
Authorization: Bearer <用户A的Token>
后端逻辑仅验证Token有效性,未检查文章ID 12345是否属于用户A。若用户A将ID改为12346(他人文章),仍可获取数据。
漏洞挖掘与验证步骤
-
识别敏感操作:
- 列出所有需权限控制的功能(如用户资料修改、订单查询、管理员后台)。
- 关注URL参数(如
?id=xxx)、请求体参数(如{"userId": "xxx"})。
-
修改参数测试越权:
- 水平越权:登录用户A,尝试访问属于用户B的资源(如将
/api/orders/100改为/api/orders/101)。 - 垂直越权:普通用户尝试访问管理员接口(如将
/user/dashboard改为/admin/dashboard)。
- 水平越权:登录用户A,尝试访问属于用户B的资源(如将
-
工具辅助:
- 使用Burp Suite的"Compare Site Maps"对比不同权限用户的接口范围。
- 自动化扫描器(如Arachni)检测常见越权模式。
防护方案
-
强制权限校验:
- 所有敏感操作需经过后端统一的权限检查中间件,例如:
# 伪代码示例:校验数据归属权 def get_user_post(post_id): current_user = get_current_user() post = Post.query.get(post_id) if post.user_id != current_user.id: raise PermissionDeniedError() return post -
最小权限原则:
- 用户默认仅拥有最低必要权限,角色权限分离(如RBAC模型)。
-
不可预测的标识符:
- 使用随机UUID替代自增ID(如
/api/posts/a1b2c3d4而非/api/posts/123)。
- 使用随机UUID替代自增ID(如
-
自动化测试:
- 编写单元测试模拟不同角色用户访问受限资源,确保返回403状态码。
-
日志与监控:
- 记录越权访问尝试,实时告警异常行为(如同一Token频繁访问不同用户数据)。
进阶案例:基于条件的访问控制漏洞
场景:博客平台允许用户编辑文章,但需满足两个条件:
- 用户是文章所有者。
- 文章状态为“草稿”。
漏洞代码:
UPDATE posts SET content = '恶意内容'
WHERE id = 123 AND status = 'draft'; -- 未校验用户身份!
攻击者可通过修改ID编辑他人草稿文章。
修复方案:
UPDATE posts SET content = '恶意内容'
WHERE id = 123 AND user_id = 当前用户ID AND status = 'draft';
总结
不安全的访问控制本质是信任边界模糊。防护核心在于:
- 服务端强制校验:永不信任客户端传递的参数。
- 权限与数据绑定:查询数据时自动关联当前用户身份。
- 标准化框架:使用Spring Security、CASL等成熟框架减少手动实现误差。