不安全的直接对象引用 (IDOR)
1. 定义
不安全的直接对象引用 (Insecure Direct Object Reference, IDOR) 发生在应用根据用户提供的输入(如 URL 中的数据库 ID)直接提供对对象的访问,但未验证该认证用户是否有权访问该特定对象时。
在 OWASP API 安全 Top 10 中,这被归类为 BOLA (Broken Object Level Authorization, 失效的对象级授权)。
2. 技术原理
假设一个 URL:https://api.site.com/invoices/1001。 后端代码可能如下:
app.get('/invoices/:id', (req, res) => {
// 易受攻击:仅检查了用户是否登录,但未检查其是否拥有发票 #1001
if (!req.session.user) return res.status(401);
const invoice = db.find(req.params.id);
res.json(invoice);
});攻击者只需将 1001 改为 1002, 1003 等,即可下载系统中的每一张发票。这里的“直接对象引用”是 ID 1001,“不安全性”则源于缺乏所有权校验。
3. 攻击流程
sequenceDiagram
participant Attacker as 攻击者
participant API
participant DB as 数据库
Attacker->>API: GET /invoices/1001 (攻击者自己的 ID)
API->>DB: 查询 ID 1001
DB-->>API: 返回发票 1001
API-->>Attacker: 200 OK (正常显示)
Note over Attacker: 攻击者注意到 ID 是连续的。
Attacker->>API: GET /invoices/1002 (受害者的 ID)
API->>DB: 查询 ID 1002
Note right of API: 应用未能检查:<br/>“用户 A 是否拥有发票 1002?”
DB-->>API: 返回发票 1002
API-->>Attacker: 200 OK (数据泄露)4. 真实案例:First American Financial (2019)
目标: 第一美国金融公司 (First American Financial Corp,大型产权保险商)。 漏洞类别: IDOR / BOLA。 泄露数据: 8.85 亿条记录。
技术背景: 该公司网站通过如下 URL 结构提供文件图像: fastweb.firstam.com/documents/view?docId=1234567 访问这些文档不需要身份验证(或验证极弱)。关键在于,文档 ID 是连续递增的。
攻击经过: 一名房地产开发商发现,只需在 URL 中更改 ID 即可查看他人的税务记录、电汇交易收据和驾照图像。 这种简单的遍历操作让他能够访问自 2003 年以来近 10 亿条敏感的财务记录。
影响: 导致了巨大的声誉损失和监管罚款。这是一个教科书般的案例,展示了简单的顺序 ID 如何导致灾难性的泄露。
5. 深度防御策略
A. 每次访问都执行授权检查
这是唯一的根治方法。 绝不假设用户登录了就有权访问。
逻辑实现:
const invoice = db.find(id); if (invoice.ownerId !== req.session.userId) { throw new ForbiddenError("您无权访问此资源"); }中间件: 使用策略中间件(如 CASL, CanCan)来集中实施“资源所有权”规则。
B. 使用间接或随机引用 (UUID)
不要在公开 ID 中使用自增整数 (1, 2, 3)。
- UUID: 使用 UUID (如
550e8400-e29b-41d4-a716-446655440000)。它们是不可预测的,无法被遍历(Enumeration)。 - 映射表: 在 Session 查找表中将内部 ID (1) 映射到外部随机令牌 (abc-xyz)。
- 注意: UUID 只能防止“遍历”,但不能解决根本的权限问题。如果攻击者通过某种方式拿到了 UUID,且系统缺乏权限验证,他们依然可以访问。防御 A 依然是必须的。
C. 自动化测试
IDOR 很难被常规扫描器发现,因为扫描器不理解“业务逻辑”(即谁拥有什么)。
- 编写集成测试,明确模拟:以用户 B 的身份登录,尝试访问用户 A 的资源。
