第三章 API1:失效的对象级授权 — 原理与测试

对象级授权漏洞,说白了就是攻击者能通过修改请求中的某个 ID,访问到他不该看到的资源。比如你改一下 URL 里的 user_id=1001 为 user_id=1002,结果别人的订单、病历、银行流水全出来了。这就是对象级授权失效。

在 OWASP API Security Top 10 里,这个漏洞排第一位,你想想看为什么?因为它在真实世界里太常见了。我个人做过上百场 API 渗透测试,几乎每次都能挖到几个这种问题。很多团队把精力都花在 SQL 注入、XSS 上,反而把最基础的授权检查给漏了。

3.1 漏洞的本质

对象级授权指的是:API 在处理某个具体资源(比如一个文件、一条订单、一个用户信息)之前,必须先验证当前用户对这个资源有没有操作权限。说白了就是问一句:“你有资格动这个 ID 的东西吗?”

但很多开发者只做了功能级授权(比如判断是不是“管理员”角色),没有检查特定对象是否属于这个用户。举个例子:

  • 用户 A 只能访问自己的订单,但 API 只检查了 “用户已登录”,没检查 “订单 owner == 当前用户”
  • 攻击者遍历订单 ID 1 到 10000,就能把全站订单信息拖走

关键区分

对象级授权 ≠ 功能级授权。功能级授权管的是“能不能调用这个接口”,对象级授权管的是“能不能访问这个接口里的某个具体 ID 资源”。两个都要做,缺一不可。

3.2 常见攻击场景

我在项目中遇到过无数次类似的案例,给你列几个典型场景:

场景攻击方式影响
水平越权(横向)修改其他用户的 ID查看/修改他人数据
垂直越权(纵向)低权限用户访问高权限接口执行管理员操作
IDOR(不安全的直接对象引用)直接枚举数字 ID批量数据泄露
批量赋值在请求体中添加不属于自己的对象 ID篡改归属关系

这里面最恶心的其实是水平越权,因为你很难用传统 WAF 检测。攻击者发的请求完全合法,只是把参数里那个 ID 换了一下。

3.3 测试方法论

我个人习惯做对象级授权测试时,按下面几步走,效率很高:

  1. 信息收集 — 记录所有带有 ID 参数的端点,比如 /api/users/{id}、/api/orders/{orderId}、/api/files?fileId=xxx。
  2. 创建两个测试账号 — 账号 A 和账号 B,分别获取它们的合法资源 ID。
  3. 替换测试 — 用账号 A 的 去访问账号 B 的资源 /api/orders/456,看能不能成功。
  4. 遍历测试 — 尝试把 ID 从1开始递增,或者用 UUID 格式的也试随机值,看是否有未授权响应。
  5. 方法测试 — 同样的 ID 换不同的 HTTP 方法(GET、PUT、DELETE、PATCH),有时候 GET 访问不了,但 DELETE 却可以。

这里有个小技巧:很多 API 在 JSON 请求体或者嵌套结构里也藏着 ID,比如 {"order": {"id": 123, "items": [...]}}。别忘了测试这些隐蔽的参数。

避坑指南

我曾经遇到过一个案例,API 对 GET /api/records/123 做了授权检查,但是 POST /api/records/batch 传一个 ID 列表时没做逐项检查。结果攻击者通过批量接口一次性拖走了 5000 条记录。记住:批处理接口的授权检查不能只在入口做,要对每个对象做。

3.4 实战测试示例

假设目标是一个电商 API,我们先注册两个用户 user_a 和 user_b,拿到各自的 。

# 使用 user_a 获取自己的订单
GET /api/orders/1001
Authorization: Bearer _of_user_a

# 正常返回:HTTP 200,订单数据

# 现在换成 user_b 的 ,但访问 order 1001
GET /api/orders/1001
Authorization: Bearer _of_user_b

# 如果返回 HTTP 200 + 订单数据 => 存在对象级授权漏洞!

如果改成 PUT /api/orders/1001 并且 body 里修改了收货地址,结果也能成功更新 user_a 的订单,那就是更严重的问题——不仅越权读取,还能越权写入。

我一般还会测试 URL 参数和 body 同时传 ID 的场景,比如 POST /api/cart/addItem?cartId=200 同时 body 里有 {"productId": 999},看后端到底用的哪个 ID 做授权判断。

测试提示

如果 ID 是 UUID 格式,别放弃测试。很多系统生成的 UUID 是按时间戳+MAC地址算出来的,在一定程度上仍有可预测性。而且即使不可预测,只要后端没做授权检查,攻击者通过别的渠道拿到一个 ID(比如从公开的评论里看到订单号)就能直接访问。

3.5 知识体系框架

下面这张图总结了本章的核心逻辑:从对象级授权失效的根源,到攻击路径,再到测试步骤和防护要点。

API1:失效的对象级授权 知识框架 对象级授权漏洞 水平越权/垂直越权 IDOR 直接对象引用 批量赋值/未授权接口 1. 信息收集列出ID端点 2. 创建两个测试账号 3. 替换ID + 遍历测试 不同HTTP方法都测一遍 批处理接口逐项检查 请求体和URL中重复ID 核心原则:谁创建的资源,谁才能访问 💡 渗透测试核心 身份 ≠ 授权

3.6 如何防范

说实话,修复这个漏洞本身并不复杂,难的是在代码的每个角落都覆盖到。说说我的建议:

  • 统一授权中间件 — 写一个类似 checkObjectAccess(user, resourceType, resourceId) 的函数,所有处理具体资源的接口都调用同一个逻辑。
  • 永远不要信任客户端传的 ID — 资源 ID 应该从 session 或 中提取用户身份,再通过数据库关联查询来获取合法 ID,而不是直接依赖客户端提交的参数。
  • 批量操作逐条校验 — 如果 API 接收一个 ID 列表,循环里每条都要调用授权检查,不能只在进入循环前检查一次“当前用户是否有批量操作权限”。
  • UUID 不是银弹 — 就算用了不可预测的 UUID,如果授权检查缺失,攻击者只要从某个泄露渠道拿到一个 ID 就能越权。授权逻辑不依赖 ID 的可猜测性。

快速检查清单

写完一个带 ID 参数的新接口,问自己三个问题:

  1. 这个 ID 对应的资源,当前用户有权访问吗?
  2. 如果换成别的 HTTP 方法(比如 DELETE),检查还在吗?
  3. 如果 ID 出现在请求体里,检查还在吗?

3.7 本章小结

对象级授权失效排名 API 漏洞之首,一点不冤。我做了这么多年渗透,几乎每个被测系统都能找到至少一个这种问题。你只要在写接口时多花几秒钟问一句“这个资源的 owner 是谁”,就能防住大部分攻击。

嗯,测试的时候记得把 IDOR 和水平越权捆绑着测,特别是那些嵌套 JSON 里的 ID、批量接口里的 ID 列表,往往是最容易遗漏的角落。我曾经就因为漏测了批量接口,后来客户上线第一天被人拖了库。从那以后我再也不敢跳过批量接口的授权测试了。