访问控制漏洞(越权)指应用程序不能正确限制用户操作自己无权访问的资源;不安全的直接对象引用 IDOR 是其中常见的一种——应用直接用用户提供的 ID 查询资源却没校验归属,改个数字就能看别人的订单或改别人的资料。治本靠服务端每一次访问都做归属与权限校验。
认证管“你是谁”,这一节转向“你能看什么”。访问控制问题最阴险的地方在于:正常操作里所有请求都是合法的,只有攻击者把资源 ID 改成别人的时才会暴露。它容易藏在“看着能跑”的功能里,测试若不刻意改参数很难发现。
假设查看订单详情接口是:
GET /order?id=123 响应: 显示订单 123 的详情
如果应用只按 id=123 查出订单显示,却从不检查“这位登录用户是不是订单 123 的所有者”,那么攻击者把 123 改成 124、125……就能顺序看光所有用户的订单。这就是典型 IDOR——资源引用直接暴露,且缺少归属校验。
问题不在于“能不能查到这张订单”,而在于“查之前有没有确认这张订单属于当前用户”。缺失的是那个与供应商无关、与查询能力无关的授权判断。越权还包括横向(看别人的同级别数据)与纵向(普通用户摸到管理员接口)两类。横向越权靠资源归属校验堵,纵向越权靠角色与权限判定堵。
很多应用靠“前端隐藏按钮”来掩盖权限,这只是皮相——接口本身仍是公开可调。前端隐藏提高不了安全性,只是让正常用户看不到入口,攻击者绕开界面直接调接口立刻见底。
越权还会掺杂“对象类型”的差异:有的场景里资源本身不敏感,但通过资源能顺藤摸到更敏感的东西。比如一个只暴露“订单号”的接口本身没数据,但攻击者用这个订单号再去调“运单详情”,就凑齐了收货人姓名与地址。所以排查越权时,不光检查“当前接口是否校验归属”,还要问“这个 ID 能不能作为下一步攻击的钥匙”。权限边界要在整条接口链上贯穿,而不仅是单点。
越权的危害常在事故后复盘时才被看清。它不是“某用户看到了 VIP 内容”这种轻伤——横向越权一旦配合批量枚举,等于把数据库中同类的全量数据一次拖走,被恶意使用和再次出售的组合空间很大;纵向越权摸到后台后,攻击者通常不再局限于“读”,而是结合管理功能做数据篡改或账户操作。加上这类漏洞在自动化扫描里常被漏掉(扫描器难猜正确的对象 ID),它实际存活周期往往比注入类更长,被发现时的积累危害也更大。这也是为什么“换对象再试”这种人工姿势如此关键——机器不一定帮你找到它,人却可以用最低成本把它钓出来。
💡 关键直觉:越权检测的抓手是“换个资源对象再试”。收到“某人能看到他人数据”的报告,先复现的姿势就是改一个 ID/所有权字段,看响应是否照常返回本人之外的数据——这是最直接有效的判别。
背景:一个多用户的留言应用,消息详情按 ID 查询且不校验归属。操作:用 A 账号登录,浏览器直接改 URL 里的消息 ID 为 B 账号的一条消息,观察返回。结果:A 看到了 B 的私信正文,横向越权判定成立。解读:查询能力正常,缺的是授权判定。变式:给查询服务加一道“消息 owner 是否等于当前用户”的校验,A 再访问 B 的消息即返回无权访问;再把管理员接口的入口校验补上,纵向越权同样封死。
越权最容易被“跑通了没报错”放过。给一个能融入日常的姿势:每次功能联调都用两种身份各测一遍——用普通用户身份核对“能看到哪些资源”,再用另一个账号去改 ID 访问,专门验证“这份数据归不归我”。把这类检查写成回归用例脚本,比临时人工测试可靠得多。更进一步,把“资源归属当前用户”的断言下沉到公共查询层而不是每个接口各写各的,能让新接口默认就带上校验,杜绝“个别接口忘了加”的漏网。
越权还有容易被忽略的时间维度:删除资源后,旧链接是否仍可访问(时序越权);角色变更后,新角色权限是否即时收口生效。这两类边角不看,越权排查就只覆盖了“改数字”这一种最浅形态,测不到更真实也更难抓的形式。把归属校验、时序、角色收口一起织进测试清单,访问控制的防线才算完整。
那招“换个资源对象再试”很有效,但新手常只想到换 ID。配一组合适的枚举变量,姿势才完整:不只是数字 ID,还有 UUID 也能被猜中或泄露出来、对象在 URL 路径上传参、对象在请求体或查询参数里、批量接口的 id 列表里混进他人的 ID、导出下载接口把筛选条件当参数传。把这些位置列入“换对象”的检查清单,排查越权时每个都试一遍,就能覆盖 IDOR 最常见的几种落位,而不是只盯着最显眼的那一个数字参数。把这些枚举变量沉淀成团队的越权检查模板,新接口都能照表快速扫一遍。