IDOR 越权漏洞的原理和防御
FreeGuideOnline
最新
2026-07-10
https://example.com/payslip?id=1234
用户 ID 为 1001 的员工能看到自己的记录。但如果他把 URL 中的 `id` 改为 `1235`,并成功看到了另一位员工的工资单,那么这里就存在 IDOR 漏洞。服务器只验证了用户是否登录,却没有检查用户是否有权访问 `id=1235` 对应的资源。
现实中的对象引用不一定是数字 ID,也可能是 UUID、用户名、文件名、哈希值等,只要是能被用户推测或枚举的引用,都可能导致 IDOR。
## IDOR 漏洞的核心原理
IDOR 的本质是**信任用户输入**。具体来说,它源于以下两个问题:
1. **未实施权限检查**:服务器在返回资源前,仅校验了请求是否来自已认证用户,但没有判断该用户与所请求资源的归属关系。
2. **可预测的对象引用**:应用使用了顺序 ID、可枚举的用户名等易于猜测的标识符,攻击者能够通过遍历发现未授权资源。
多数 IDOR 漏洞的产生路径是:
- 用户通过某种身份认证(如登录)获取会话。
- 在后续请求中,客户端携带资源标识符(ID、key 等)向服务器索要数据。
- 服务器从数据库或文件系统中取出对应资源,直接返回给客户端,期间缺失了**权限归属验证**这一步。
如果一个银行应用通过以下接口查询账户余额:
GET /account?id=188291
且仅靠前端页面隐藏了其他用户的 ID,那么任何登录用户都可以通过修改 `id` 参数查看任意账户余额——因为后端只是机械地根据 `id` 去数据库查询并返回结果。
## IDOR 漏洞的常见表现形式
IDOR 不只出现在 GET 请求中,也不仅限于读取操作。以下场景都可能是 IDOR 的高发区:
- **基于 ID 的 API 端点**:`/api/users/1024/profile` 修改他人资料。
- **POST/PUT 请求体中的对象引用**:`{“order_id”: 8877, “status”: “cancelled”}` 取消他人订单。
- **文件下载或图片访问**:`/download?file=contract_334.pdf` 下载他人合同。
- **隐藏参数或 cookie**:请求中含有 `current_user_id=665`,被客户端篡改。
- **批量赋值**:更新个人资料时传入 `{“name”: “attacker”, “role”: “admin”}`,错误地允许修改敏感字段。
- **GraphQL 查询**:未对查询字段做权限过滤,导致通过关联 ID 获取他人数据。
**关键点**:很多开发者误以为“只要把 ID 换成 UUID 或者用 hash 就安全了”,但这仅仅是**模糊化引用**,并非真正的访问控制。如果攻击者通过其他途径获取了他人的资源标识符,漏洞依然存在。
## 两种容易被混淆的错误观念
### 1. 将 IDOR 与参数篡改完全等同
IDOR 是参数篡改攻击的一种结果,但并非所有参数篡改都是 IDOR。IDOR 特指**对资源标识符的直接引用**导致越权,而参数篡改的范围更广(如修改金额、修改权限标志等)。即便是修改权限的漏洞,如果它不涉及对象引用,也不归为 IDOR。
### 2. 认为“复杂 ID 能治愈 IDOR”
使用 UUID、随机字符串、加密的 ID,只能增加攻击者**发现**有效引用的难度,无法从根本上解决权限校验缺失的问题。一旦攻击者通过泄露、共享链接、暴力穷举(短期随机数仍可穷举)等方式获得他人的对象引用,漏洞依然会被触发。**真正的解决方案始终是强健的服务端访问控制**。
## IDOR 漏洞的挖掘与检测方法
对于安全测试人员或开发者自查,可以通过以下步骤验证系统是否存在 IDOR:
### 手动检测思路
1. **创建两个不同权限的账号**(如用户 A 和用户 B)。
2. **拦截并观察**用户 A 访问自己资源的请求,找出代表对象标识的参数。
3. **替换为属于用户 B 的对象标识**,使用用户 A 的会话重新发送请求。
4. 如果响应中返回了用户 B 的资源数据,或成功操作了用户 B 的资源,则说明存在 IDOR。
5. 检查所有可能的位置:URL 路径、查询字符串、POST body、自定义 Header、Cookie 等。
### 自动化辅助工具
- **Burp Suite 的 Autorize 插件**:自动用低权限用户的 cookie 重放高权限接口的请求,对比响应差异。
- **自定义脚本**:通过拼接自增 ID 批量请求敏感接口,监测响应包大小或内容特征。
- **Postman + 环境变量**:快速切换不同用户的 token 和 ID 进行测试。
## IDOR 的防御措施(分层与实践)
防御 IDOR 不能依赖客户端混淆,必须由服务端彻底落实访问控制。推荐采用**纵深防御**策略,将多种手段结合使用。
### 1. 强制实施服务端权限校验
这是唯一治本的方法。每次请求涉及资源操作时,都必须验证当前用户是否有权限访问该资源。思路通常有两种:
- **基于所有权的校验**:检查资源的 `owner_id` 是否等于当前登录用户的 ID。适用于博客、订单、文件等有明确归属的资源。
- **基于权限模型的校验**:使用 RBAC(基于角色的访问控制)或 ABAC(基于属性的访问控制),判断用户是否具备特定的操作权限。例如,只有“管理员”可以查看所有订单,普通用户只能查看自己的。
权限校验逻辑最好封装在公共层(中间件、服务层、ORM 钩子中),避免在每个接口中重复编写,减少遗漏。
### 2. 使用非直接引用(间接引用映射)
在服务端维护一张**临时、随机的引用映射表**,客户端只持有服务端生成的、无实际含义的 token(如 `payslip_token=aB3x9Qz`),服务端再据此查找真正的资源 ID。这种方法虽然不能替代权限检查,但大大缩小了攻击面,与权限校验配合使用时效果很好。
### 3. 避免暴露可预测的对象标识
如果必须在 URL 中使用资源标识,尽量使用 UUID v4(随机)或 Nanoid 等不易被枚举的格式。但必须牢记:这仅仅是防护第一层,绝不能以此替代权限校验。
### 4. 采用“属主过滤”的数据访问模式
在数据库查询时,始终带上当前用户的身份条件。例如:
```sql
SELECT * FROM orders WHERE order_id = ? AND user_id = ?