你是否想过,某些看似不起眼的权限设计缺陷,在特定条件下会变成严重的业务逻辑漏洞?今天要探讨的这个思路就相对比较新颖,它将常见的 IDOR 与一个关键的时间窗口结合了起来。

上图揭示了一个典型的场景:API 接口通过整数 orderId 参数来查询订单详情。这听起来就是一个标准的 IDOR(不安全的直接对象引用)漏洞。简单替换订单号,你就能查看甚至劫持他人的订单——但这里有一个重要的前提:仅限于订单尚未完成时。
图中被高亮的订单号是 10099780。常规测试中,如果你把它加 1 变成 10099781,服务器很可能返回 404(不存在)或 403(无权限)。但如果你持续向上枚举,例如尝试 10099788,可能会惊喜地发现它突然返回了 200 状态码,并给出了完整的订单数据。
奇怪的是,稍等片刻后再去访问 orderId=10099788,它又变回了 403。继续向上加几个数字,你可能又会找到新的可访问订单,但同样,几秒钟后访问权限就消失了。
经过一番琢磨,你可能会恍然大悟:在订单完成(例如支付)之前,系统的访问控制机制并未生效;只有在订单完成之后,严格的权限检查才被激活。
这意味着一个清晰的逻辑链:
- 未完成订单 → 任何人只要知道
orderId 就能访问。
- 完成订单 → 权限校验生效 → 正常拦截未授权访问。
站在攻击者的角度,这其中的风险有多大?
想象一下这个场景:攻击者可以修改他人尚未完成订单的收货地址。后果就是,受害者正常付款,商品却被寄到了攻击者指定的地址。攻击者无需花费一分钱就得到了商品。
当然,攻击面远不止于此。攻击者还可能:
最终的结果都指向一点:攻击者能够获得大量商品或服务,却无需承担相应的费用。 这对企业而言,无疑是直接的财务损失。
攻击模拟示例
让我们用一个具体的例子来加深理解。
攻击者通过脚本持续枚举订单ID:
GET /api/orders/details?orderId=13580
GET /api/orders/details?orderId=13581
GET /api/orders/details?orderId=13582
...
当枚举到某个刚刚创建、但用户还未支付的订单时(例如orderId=13588):
GET /api/orders/details?orderId=13588
服务器返回 200,并包含了该订单的详情。
攻击者立即发起修改请求:
POST /api/orders/update
{
orderId: 13588,
shippingAddress: "攻击者地址"
}
几秒后,真正的订单所有者用户 A 完成了支付。然而,收货地址早已在支付前的瞬间被篡改。商品将按照被修改的地址发出。
这个漏洞的窗口期极短,但足以被自动化工具利用:
创建订单 → 未支付 → 可被他人访问 → 支付完成 → 权限锁上
攻击者只需要在“未支付”这几秒甚至更短的时间内,抢先访问并修改订单即可。
核心结论就是:并发测试 + IDOR = 可劫持未完成订单。 这种漏洞往往隐藏在业务逻辑深处,需要测试者对系统状态流转有深刻的理解才能发现。
欢迎在 云栈社区 的安全板块与更多同行交流此类业务逻辑漏洞的测试心得。
往期回顾
参考来源
z-wink推特
|