本文目录导读:

水平越权(Horizontal Privilege Escalation)是指攻击者利用漏洞,访问或操作与自己同级别但属于其他用户的数据或功能(普通用户A查看或修改了普通用户B的订单)。
预防水平越权没有单一的“银弹”,需要从架构设计、编码规范、访问控制、数据隔离等多个层面进行综合治理,以下是核心的预防策略:
核心原则:基于用户身份的细粒度访问控制
这是最根本的预防措施。永远不要信任用户传入的ID(如 user_id、order_id)来标识“谁”在操作。
-
从Session/Token中获取当前用户ID: 不要从前端请求的参数(如URL的
?user_id=123)中获取当前操作者的身份,必须从服务器端维护的安全会话(Session)或签名的JWT(JSON Web Token)中提取。 -
绑定数据所有权: 在执行任何涉及用户数据的操作(查询、修改、删除)前,必须验证该数据的所有者ID是否等于当前登录用户的ID。
代码示例(避免):
# 危险!直接使用URL传入的user_id user_id = request.GET.get('user_id') order = db.get_order(order_id, user_id=user_id) # 用户A可以传入user_id=B来查B的订单 return order代码示例(推荐):
# 安全!从Session获取当前用户ID current_user_id = session['user_id'] order = db.get_order(order_id) # 关键检查:确保订单属于当前用户 if order.user_id != current_user_id: raise PermissionDenied("无权访问该订单") return order
架构设计:消除或替代可预测/可枚举的资源ID
水平越权常利用可枚举的ID(如自增ID、连续数字)遍历其他用户的数据。
- 使用UUID或哈希ID: 将自增整数ID替换为全局唯一标识符(UUID,Universally Unique Identifier)或非连续的哈希ID,这能防止攻击者通过简单递增ID来猜测其他用户的数据。
- 使用间接引用: 不让用户直接传递“订单ID”,而是传递一个“订单访问令牌”或“引用ID”,服务器内部映射回真实ID,这样外部无法获取真实ID的规律。
后端API设计:参数绑定与校验
-
拒绝无关参数: API接口只接收处理当前业务逻辑所必须的参数,如果接口需要查询当前用户的订单,就不应该设计成接收
other_user_id作为参数。 -
强制绑定上下文: 在后端服务的Service层或数据访问层,强制将查询条件与当前用户ID绑定。
例子:一个查询用户订单列表的API,后端SQL应类似:
SELECT * FROM orders WHERE user_id = :current_user_id,而不是SELECT * FROM orders WHERE user_id = :requested_user_id(除非是管理员功能)。
测试与审计机制
- 渗透测试专项: 在安全测试中,专门针对所有带有“用户特定数据”的接口进行测试,测试方法:用户A登录,记录所有操作,然后使用用户B的Token或Cookie,尝试调用用户A曾操作过的API(修改用户A的ID、订单ID等)。
- 动态权限检查: 使用自动化工具(如Burp Suite的Autorize、AuthMatrix插件)批量扫描所有API端点,检查是否存在未授权的跨用户数据访问。
- 日志审计: 记录所有对敏感数据的访问操作,包括操作用户ID、操作对象ID、操作类型和时间,一旦发生越权泄漏,可以追溯和分析。
特殊的场景处理
- 文件/资源访问: 访问其他用户上传的文件(如头像、附件)时也要注意,如果文件路径或ID是可预测的(如
/files/user_123/photo.jpg),业务逻辑也必须验证当前用户是否有权访问该路径下的文件,通常建议使用专门的文件服务,并基于Token校验。 - 缓存与CDN: 如果CDN或缓存服务器没有正确配置,攻击者可能通过猜测或遍历资源的URL来访问其他用户的私有内容,确保动态、私有的用户内容使用鉴权URL或私有缓存策略。
预防水平越权的“黄金法则”
| 层面 | 核心操作 | 为什么这样做 |
|---|---|---|
| 身份识别 | 从Session/Token获取用户ID,绝不信任前端传入的ID。 | 防止攻击者伪装成其他用户。 |
| 权限校验 | 在每一次数据访问前,检查数据的所有者是否等于当前用户。 | 确保操作在合法范围内。 |
| ID设计 | 使用UUID/哈希ID替代自增整数ID。 | 增加猜测和遍历的难度。 |
| 接口设计 | API只接受必要参数,拒绝无关的用户标识。 | 减少攻击面。 |
| 测试验证 | 定期进行跨用户越权专项渗透测试。 | 发现隐藏的漏洞。 |
简单一句话:服务端永远要问一句:“这个数据,你真的有权利动吗?”