越权:扫描器永远发现不了的那类漏洞

在 SRC 里,越权大概是投入产出比最高的一类漏洞。不需要特殊工具,不需要绕过 WAF,会改数字就行。

但它也是扫描器永远发现不了的一类。原因很简单:扫描器不知道”这条数据属于谁”。

SQL 注入有 payload 特征,XSS 有反射点,越权什么都没有——它就是一次完全正常的请求,只不过请求里的 ID 换成了别人的。

扫描器的盲区在哪

所有自动化工具判断漏洞,靠的是”输入触发了异常输出”。注入让数据库报错,XSS 让脚本执行,路径穿越读出 /etc/passwd,都有明确的信号。

越权没有信号。你请求 /api/order/1002,服务器返回 200 和一份订单详情,格式正确、字段完整、没有任何异常。唯一的区别是:这份订单不是你的。

要判断”是不是你的”,工具得知道当前登录用户是谁、这份数据归属谁、两者是否匹配。这三件事都在业务逻辑里,扫描器一概不知。

所以越权只能人工测,而且必须用两个账号对照。一个账号自己测自己,永远测不出来。

三类,测法不一样

类型 本质 典型测试点
水平越权 同角色,跨用户 订单号、用户 ID、文件 ID、消息 ID
垂直越权 低权限访问高权限功能 后台接口、管理接口、审核接口
未授权访问 根本不用登录 接口漏了鉴权中间件

水平越权最常见,也最好挖。找所有带数字 ID 的请求,用自己的账号发一次,把 ID 改成别人的,看返回什么。

关键在于怎么拿到”别人的 ID”。这一步往往比越权本身难。有时候它出现在列表页的响应里,有时候在分享链接里,有时候会被前端加密。

垂直越权的入口通常藏在 JS 里。前台页面看不到后台菜单,但接口路径写在前端代码里,或者全站共用一个 /api/admin/* 前缀。用低权限账号直接请求,看是不是 403。

未授权访问最好找也最容易被忽略:退出登录,把之前抓到的请求重放一遍。返回 200 就是洞。

几个具体手法

改 ID 是最基础的。但直接改数字经常失败,因为很多系统用了自增 ID 之外的方案。这时候换个思路:

改参数名。前端传 userId=1001,后端可能同时接受 uid、user_id、id。加一个参数试试,有些框架会自动绑定。

删参数。把 userId 整个删掉,看后端是不是从 session 里取值。如果返回的数据变了(变成当前用户自己的),说明后端有兜底;如果报错或者返回了别人的,说明它依赖前端传值。

换 HTTP 方法。GET 有鉴权、POST 没有,是常见的不一致。同一个接口用 PUT、DELETE 再试一遍。

改 Content-Type。JSON 转表单、转 XML,有些框架的鉴权中间件只对特定类型生效。

看子资源。主接口校验了归属,但 /order/1002/items 这种子路径经常漏。同样,导出、打印、分享、预览这些”附加功能”最容易漏鉴权。

怎么判断”真的越权了”

返回 200 不等于有洞。有三种情况要分清:

一、返回了别人的数据。最直接。看响应里的用户名、手机号、地址,是不是你自己账号的。不是,就是洞。

二、返回 200 但内容为空。可能是后端做了归属过滤,查不到就返回空数组。这种情况不是洞,但说明接口没有返回 403,值得继续试其他 ID 或子路径。

三、返回 403 但操作生效了。最阴的一种。前端显示”无权限”,但后端已经执行了删除/修改。验证方法是操作后用原账号查一次,看数据还在不在。

批量测试:两个账号 + 一份 diff

手工一个个试太慢。我的做法是准备两个账号(A 是自己的,B 是另一个),然后用工具把 A 的所有请求打到 B 的 token 上,对比响应。

关键是记录三件事:请求路径、A 的响应长度、B 的响应长度。长度接近但不完全一样,往往就是”查到了不同的记录”,值得人肉看。

这一步不用写复杂脚本,Burp 的 Autorize 插件就是干这个的:配置一个低权限 cookie,它会自动把每个请求用这个 cookie 重放,然后标红那些”本来该被拦但没被拦”的。

但要注意:Autorize 只能告诉你”没被拦”,不能告诉你”泄露了什么”。标红的请求还得人肉看响应。

写报告:别写”可导致数据泄露”

SRC 审报告的人每天看几十份,最烦的就是影响描述全是套话。

“攻击者可越权获取其他用户信息,造成严重数据泄露” —— 这句话没有任何信息量。

换成这样:

“使用 A 账号(user_id=1001)请求 GET /api/order/1002,返回了 B 账号的完整订单,包含收货人姓名、手机号、详细地址、下单商品。该接口为自增 ID,遍历 1000-2000 可批量获取约 1000 条真实订单。”

区别在于:具体的接口、具体的字段、具体的量级、具体的遍历成本。审核的人一眼就能判断危害等级。

还有一点,复现步骤要能让别人照着跑通。我见过报告里只写”修改订单 ID 可实现越权”,连是哪个请求都不说。

为什么这类漏洞修不完

因为它不是技术问题,是设计问题。

SQL 注入有标准解法:参数化。XSS 有标准解法:转义。越权没有——每个接口的资源归属关系都不一样,必须一个个想清楚”这个数据属于谁、谁能看”。

更麻烦的是它容易被遗漏在新增功能里。主流程上线前测过了,三个月后加了个导出功能,忘了加鉴权。这种补丁永远打不完。

能做的只有两件事:一是把归属校验收进统一的中间件,让开发者没机会忘;二是把”新增接口必须过越权测试”写进流程。

顺带说一句:别指望前端校验。前端隐藏菜单、隐藏按钮,改个请求就绕过了。所有校验必须在服务端做。

最后

这类漏洞有个特点:挖的时候觉得自己很厉害,修的时候发现满地都是。

如果你在测自己的系统,建议从一个具体功能开始——比如订单列表——把所有相关接口列出来,逐个问一句”这个接口怎么判断数据是不是当前用户的”。答案含糊的,基本都有问题。

比跑一遍扫描器有用得多。


本文仅讨论自有系统与书面授权范围内的安全测试。对未授权系统进行越权测试属于违法行为,与技术水平无关。

© 版权声明
THE END
喜欢就支持一下吧
点赞7赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容