SRC越权漏洞实战:从接口梳理到水平垂直越权挖掘
1. 越权漏洞为什么是SRC的“常青树”做SRC挖洞这几年我最大的感受就是SQL注入和RCE越来越难撞但越权漏洞就像韭菜一样割完一茬又长一茬。你登录了自己的账号结果能把别人的订单查出来、把别人的资料改掉或者一个普通员工账号直接干翻管理员后台——这类问题几乎在每个企业系统里都能翻到而且很多团队做安全测试时压根没把这当回事总觉得“反正有登录验证”。这篇文章完整拆解一次我在某企业系统里的授权测试实战从最开始的思路梳理、接口整理到最终提交多个越权漏洞每一步都还原当时的判断逻辑和实操动作。无论你是刚开始接触SRC的新手还是要做企业自研系统安全评估的同行这篇内容应该都能帮你省掉不少试错的功夫。1.1 从一次“运气好”的提交说起这次测试的起因是某SRC平台给了一批授权范围内的测试目标。我一开始的思路还挺传统先扫目录、翻JS、找API接口想着能不能撞出个SQL注入或者未授权访问。结果一整天下来常规漏洞一个没捞到系统本身的安全基线做得比我预想中扎实。后来我换了个思路既然硬骨头啃不动那就把重心放在业务逻辑上。我把所有带id、uid、orderId这类参数的接口全部提取出来逐个替换身份标识做对比测试。结果当天下午就连续挖到了三个不同业务模块的越权漏洞其中两个被定级为高危还有一个涉及到批量数据导出直接拉高了影响范围。这不是什么玄学操作。企业系统做到一定规模功能模块越加越多前后端分离之后权限校验的逻辑经常散落在各个微服务和接口里。只要有一个环节只校验了“是否登录”而没有校验“数据归属”越权就出来了。而业务逻辑漏洞恰恰是很多自动化扫描器覆盖不到的盲区所以挖掘的性价比特别高。1.2 越权漏洞的分类与危害等级行业内一般把越权分成两类水平越权同一角色的用户A能访问用户B的数据。比如普通用户查看彼此的订单、简历、收货地址。垂直越权低权限角色能访问高权限功能。比如普通员工操作管理员的后台接口。还有一种容易被归入越权的是未授权访问严格来说它不算越权但危害等级往往更高尤其是在文件下载、订单导出这类接口上——连登录都不需要数据直接裸奔。SRC平台的定级标准一般是这样的能读取他人敏感数据的水平越权通常定级“中危”到“高危”如果涉及订单金额、身份证号、手机号这类强敏感数据直接高危垂直越权如果是普通用户到管理员基本也是高危起步。所以越权漏洞在SRC的性价比其实非常不错不需要多高深的利用技巧纯靠细心和对业务的理解。2. 目标梳理与功能点画像越权挖掘最怕的不是技术不够而是没想清楚“这个系统到底有哪些接口哪些接口值得试”。很多新手上来就开着Burp把站点所有请求乱点一遍全凭运气这其实很低效。我自己的习惯是先花一两个小时做信息梳理把系统的功能地图画出来然后再动手测效果完全不一样。2.1 先摸清系统到底有哪些“操作入口”第一步肯定是基于授权范围内的目标做信息收集。资产测绘那些我不展开讲了重点说说怎么从一个已经登录的Web系统里把功能入口和接口关系弄清楚。这次测试的目标是一个典型的前后端分离系统前端所有API路径都写在JS文件里。这个阶段我做了三件事用浏览器的开发者工具把JS文件里的接口路径批量提取出来按模块归类抓取页面正常操作时的请求补充JS里没有暴露的隐藏接口。比如下拉框联动、自动保存草稿、列表排序这类接口很多时候开发者会漏掉鉴权把每个接口的请求方法、参数名、当前登录身份能拿到的返回包记录下来建立一份“接口-功能-数据归属”的对应表。这里有个很容易被忽略的点高权限账号能看到比普通账号更多的接口。如果手里只有普通用户账号最好想办法注册或者申请一个更高权限的测试账号越权测试时要用它来观察“目标接口长什么样”。如果没有高权限账号就从普通用户能访问的接口往上钻也能试出不少问题。建立接口清单之后判断优先级的标准就很重要了带id、uid、orderId、taskId这类明显标识参数的接口优先返回包里有手机号、身份证号、订单金额、文件路径的接口优先只接受POST但参数很简单、没有签名机制的接口优先新旧版本的接口同时存在时旧版接口往往缺少新加的鉴权逻辑优先试。2.2 每个功能点背后的“身份逻辑”是什么这一节其实是越权挖掘最核心的思考过程。拿到接口清单之后要回答三个问题这个接口的数据归属于谁是当前登录人还是某个业务实体系统是靠什么来确定“当前是谁”的是Cookie里的session还是请求头里的token还是干脆用参数里带上来的userId如果我把业务实体ID换一下系统会拿什么来校验举一个我实际遇到的例子某个订单查询接口请求参数是orderId返回包里有订单编号、金额、收货人手机号。我先观察了自己账号正常查询时的行为发现系统是用Header里的token解析出当前用户再拿orderId去查订单但校验“这个订单是否属于当前用户”的环节缺失了。这时候把orderId换成别人订单的ID返回包照样返回全量数据。这种案例听起来特别简单但真正麻烦的是系统不一定都这么耿直。有些系统在查询时会带上userId参数很多开发想当然地认为“既然我能拿到userId那这个接口就是安全的”于是后端只校验userId对应的用户是否有效却忘了校验这个userId到底是不是当前登录人。这类接口直接在请求里改userId就能越权比改业务ID还省事。还有一种藏在“批量操作”里的越权比如导出报表接口参数是startTime和endTime看起来人畜无害。但如果你发现它有uidList这类参数把别人的uid加进去可能就直接导出了别人的数据。所以功能点画像这一步最重要的产出物不是接口列表而是一张“身份与数据归属关系表”。这张表里每一行就是一句话接口A数据归属当前用户身份来源token参数orderId疑似无归属校验接口B数据归属指定用户身份来源参数userId参数userId疑似可直接替换身份。有了这张表后面所有测试都变成了“验证猜想”效率直接翻倍。3. 实战挖掘三个典型越权场景这一节把这次实战里最有代表性的三个场景完整还原一遍。它们分别对应了水平越权、垂直越权和未授权访问三种形态基本上覆盖了越权挖掘的绝大多数情况。3.1 场景一订单查询接口的水平越权这个接口是我在JS文件里发现的路径结构大概是/api/order/detail参数是orderId。接口本身是POST请求返回的是订单详情。正常操作是我在自己的订单列表里点击某一笔订单前端用这笔订单的orderId调用detail接口返回内容里能看到收货人姓名、手机号、详细地址、订单金额、支付记录。这是再典型不过的电商订单模块。我第一时间做了两件事把orderId从正常值改成另一个随机数比如原orderId是ORD2024XXXX001改成ORD2024XXXX002直接请求对比返回包的内容差异。结果很直接改成别人的orderId之后返回包依然返回了完整的订单详情。这说明后端完全没有做“这个订单是否属于当前登录用户”的校验。这里要说一个重要的细节有些系统不是每笔订单的orderId都是纯数字或纯字符串的可能是UUID也可能是带日期前缀的复合编号。这种时候直接改一位数字大概率会得到一个“订单不存在”的返回包。别灰心这不代表没有越权而是你还没拿到别人的有效orderId。怎么拿到别人的orderId几个思路看订单列表接口是不是也越权。如果列表接口没限制直接全量拉取看评论、售后、物流信息这些关联模块它们的业务逻辑往往需要引用orderId可能在其他接口的返回包里暴露看订单号生成规则如果是日期序号可以尝试一个时间窗口内的序号遍历。回到这个案例确认单笔查询越权之后我又顺着往下试了试批量导出接口。导出接口参数里有个orderIds数组我把自己的一笔订单和别人的一笔订单同时放进去结果导出的Excel里出现了两笔订单的数据。这就从单个查询越权升级成了批量数据泄露危害级别直接拉满厂商那边也很快就确认了漏洞。3.2 场景二用户资料修改接口的垂直越权这个场景发生在系统的个人信息管理模块。我当时用的是一个普通员工账号功能是自己改头像、昵称、手机号这类基础资料。发现问题的过程挺有意思不是靠猜参数猜出来的而是靠“看返回包”看出来的。修改手机号时正常请求长这样PUT /api/user/profile参数有mobile和verifyCode。返回包里除了提示修改成功还附带了一个字段role值是EMPLOYEE。我第一反应是——这个接口居然在更新用户资料时把整个用户实体都返回了那如果我往参数里塞一个role后端会不会更新于是我构造了这样的请求把role字段从EMPLOYEE改成ADMIN同时保留mobile参数。结果返回包显示我的账号角色已变成ADMIN。这个接口的后端逻辑八成是把前端提交的整个用户对象拿去update压根没做字段白名单。普通员工直接变管理员属于教科书级别的垂直越权。后来我又在另一个子系统的用户管理后台发现了一模一样的问题管理员修改用户状态的接口/api/admin/user/status参数是userId和status没有校验当前操作人是否具备管理员权限。普通员工账号直接请求这个接口也能把别人的账号禁用掉。这件事给我的启发是垂直越权不一定都要去撞“隐藏的后台接口”有时候就藏在日常功能里——只是日常功能带了一些不该被前端控制的字段。所以看返回包、看接口文档里的字段说明比自己瞎试参数要靠谱得多。3.3 场景三文件下载接口的未授权访问前面两个场景都需要登录账号这个场景更直接连登录都不需要。系统的附件管理模块有个文件下载接口接口路径是/api/attach/download参数是fileId。正常用法是用户点击附件链接前端把fileId传给后端后端返回文件流。我先登录账号下载了一次自己的附件抓包拿到请求发现这个接口竟然没有强制校验token把请求里的身份信息全部去掉之后直接请求依然能下载成功。紧接着我把fileId换成其他数值结果能下载到其他人的附件。这些附件里有身份证照片扫描件、劳动合同扫描件。这个问题的本质是两层叠加接口既没做登录校验也没做文件归属校验。这类问题的排查思路跟前面不太一样因为它不在登录态里所以你在正常功能里是“感觉不到”它的存在的。最常见的发现路径有两种一种是像这个案例一样在正常下载附件时顺手把身份标识信息清了再重放发现还能通另一种是翻前端代码或者历史接口文档发现fileId这类参数本身没有鉴权逻辑直接拼URL请求。文件下载类越权的危害很容易被低估因为很多开发觉得“文件名/文件路径是不可猜测的”。但实际上一旦fileId是自增数字或者文件名里有时间戳规律遍历成本低到可以忽略不计。而且这类漏洞如果泄露的是合同、身份证扫描件在SRC评级里基本就是高危起步。4. 挖掘过程中的常见问题与排查技巧越权挖掘看起来门槛低但真正上手之后各种奇怪的情况都有。这一节整理了自己多次实战中遇到的典型问题和对应的排查思路很多都是文档里不会写的经验。4.1 为什么明明越权了却返回401/403我见过很多人反馈我把订单id换了结果返回401 Unauthorized或者403 Forbidden是不是不存在越权不一定。这里有几种可能系统在最外层有一个网关或者中间件会拦截不符合规范的请求。常见的情况是网关只校验“请求头里有没有token”如果你的测试姿势是直接把整个请求放Repeater里token丢了一部分网关这一层就给你拦了。这种时候先在原始请求上只改id其他什么都不动再试试系统做了“越权检测”风控比如短时间内大量请求同一个接口触发了风控策略返回403。这种属于安全策略生效不代表没有越权换个低频率、模拟正常操作的姿势再测接口本身有独立的鉴权逻辑但你没有触发它比如某些接口要求特定Header、特定签名参数。排查思路很简单先在正常请求的基础上只改业务ID一个参数保持用户身份标识不变看返回值是否变化。如果返回的是“订单不存在”这类业务错误说明系统已经在业务层校验了归属大概率没戏如果返回的还是正常数据那就继续深入在身份标识上做文章。4.2 绕过前端限制的三个思路很多系统在前端做了权限控制比如普通用户的菜单里压根没有“用户管理”这个入口于是新手觉得“访问不到没有接口”。这种思路需要马上纠正。前端只是把接口藏起来了不是把接口删掉了。后端接口如果没做权限校验那么前端限制根本不构成安全边界。三个绕过的思路直接看前端源码。前端路由和按钮权限的代码里会以字符串形式暴露所有接口路径。用浏览器的开发者工具搜索关键词比如“admin”“manage”“delete”“export”把后端地址拼出来直接请求从后端端口和服务发现入手。前后端分离架构里后端可能有独立的服务端口或者子域名。某个前端页面没接入的后台服务直接访问它的根路径有时候能拿到接口文档或者Swagger页面用不常用的请求方法。有些系统对GET和POST做了权限控制但对PUT、DELETE、PATCH或者OPTIONS没做控制。比如禁用一个用户的功能在页面上是POST /api/admin/disable你可以试试PUT /api/admin/disable或者把参数从JSON改成form-data格式偶尔就能绕过。4.3 越权漏洞的“误报”陷阱提交SRC报告之前最怕的就是误报。被厂商驳回一次不仅浪费时间还影响白帽子的信誉。最常见的误报场景是你把orderId改成别人的返回了“订单不存在”或者报错你以为是漏洞但其实系统根本没有那笔订单或者那笔订单属于一个已经被删除的用户。避免误报的核心方法必须有“同一请求、同一参数、不同身份得到不同数据”的对照实验。具体做法是用自己的两个账号A和B各自创建一条数据用A的身份请求B的数据ID如果返回B的数据铁证如山如果返回“数据不存在”再看是“业务层面确实查不到”还是“权限被拒绝”前者不要提交后者再确认是不是权限校验机制如果只有单个账号就找公开数据的ID比如订单列表里可见的、评论里展示的ID先确认目标ID的数据确实存在再测越权避免拿一个不存在的ID去测。另外一个观察点是很多系统的接口返回“500”或者“401”不是因为校验了权限而是因为接口本身对异常参数处理不好。这类情况也要判断清楚如果是因为把ID改成别人的导致程序报错那可能是越权未遂也可能是权限校验代码抛异常不要盲目提交。现象可能原因处理方式改ID后返回正常数据后端未校验数据归属确认数据敏感度后提交改ID后返回“订单不存在”业务层已过滤或ID无效换有效ID再测改ID后返回401/403网关拦截、风控或独立性鉴权保持身份标识只改业务参数改ID后返回500程序异常或鉴权代码抛错谨慎判断避免误报改身份字段后返回成功后端信任前端提交的身份字段严重越权高危提交5. 修复建议与防护体系漏洞找到了报告也提交了接下来要聊的是怎么修。很多SRC白帽子习惯性只报漏洞不管修复但如果你能提出可落地的修复方案报告的价值会明显高出一截厂商的认可度也会更高。5.1 后端鉴权永远不要在接口层相信前端越权漏洞的根源本质上是后端把“用户身份”和“数据归属”的校验分开了或者干脆漏了数据归属校验。修复的第一步是统一身份识别。登录用户的身份必须从服务端会话中获取而不是从前端参数里获取。也就是说userId、role这些字段不该出现在前端请求参数里更不该被后端当作身份来源。第二步是“数据归属校验”的标准化。在业务代码里凡是涉及查询、修改、删除数据实体的操作都必须把“当前登录用户”和“数据实体的owner”做比对。最常见的方式是先根据ID查出数据实体再比对实体上的userId字段和当前登录用户是否一致不一致直接拒绝而不是先查后放。第三步是接口层的统一权限注解或中间件。现在很多后端框架都支持在路由上声明所需的权限角色比如Spring Security的PreAuthorize应该把所有接口的权限要求显式声明出来默认拒绝需要时才放行而不是默认放行。5.2 权限模型的三种落地方式修复权限问题不是写几行if判断就完了还需要一个完整的权限模型。这里分享三种常用的落地方式RBAC模型基于角色的访问控制用户归属角色角色绑定权限接口按角色授权。最通用适合大部分业务系统缺点是细粒度的数据归属控制还是需要配合行级校验一起做。ABAC模型基于属性的访问控制根据用户属性、资源属性、环境条件动态计算是否放行。适合复杂组织架构的业务系统比如流程审批、多租户系统但实现成本高不宜一刀切全上。数据权限过滤层不纠结角色而是让所有查询SQL都自动带上数据范围条件比如“WHERE user_id 当前登录人”。实现上可以用MyBatis拦截器之类的组件统一处理减少业务代码里的重复判断。5.3 从漏洞到体系业务安全测试清单最后分享一份我在做企业系统安全评估时常用的业务安全测试清单直接在复测或自查时照着用所有的业务列表接口尝试修改页码、数量、排序字段看是否能横向越权所有带ID的详情接口尝试修改ID为其他值如果是复合ID注意测试不同字段的组合比如ticketIdeventId所有下载、导出接口尝试清除或篡改身份标识后重放所有修改接口尝试在请求体里追加没有在页面上出现的字段比如role、admin、level观察字段是否被更新所有“批量”操作接口尝试在批量ID列表里混入其他人的ID所有后台管理接口用普通用户身份测试一遍不要只看前端隐藏了没有涉及手机号、邮箱、仓库地址等资料修改的功能修改后检查是否真的校验了验证码或二次确认。这份清单不是一次性做完就完事了更重要的是形成“功能上线前必测”的流程。安全漏洞这个东西修完还存在低水平重复的根因往往是流程上没有把测试动作固化下来。我见过不少团队漏洞报了、修了过两个版本换了个业务模块又重新出现同样的问题就是因为没有把“越权自测”这件事变成强制动作。6. 写在最后这次实战挖到的三个越权漏洞从提交报告到厂商修复前后只用了一周时间。其实每个漏洞的产生原因都不复杂一个是没有做数据归属校验一个是把角色字段暴露给了前端另一个是下载接口完全缺鉴权。我个人在实际操作中的体会是越权漏洞挖掘最值钱的能力不是会多少工具而是对业务的理解——你得知道一个企业系统里哪些数据是敏感数据哪些业务流程里藏着“本不该出现的操作入口”。把这个逻辑想清楚再配合耐心的接口梳理和逐项验证你会发现越权漏洞远比想象中多。如果你正在做SRC或者企业自我安全评估建议把重心从撞SQL注入转移到业务逻辑测试上尤其是用户身份与数据归属的边界这一个点上的投入回报率比大多数漏洞类型都高。最后再分享一个小技巧提交越权漏洞报告时一定要把“影响范围”写透。不要只说“可以查看他人订单”而是要说明“通过这个接口可以批量遍历订单号大量获取收货人姓名、手机号、地址等敏感信息”。影响范围写得越清晰厂商对漏洞的定级就会越准确你的报告也更容易被认可。越权漏洞听起来名字不起眼但它在企业系统里的生命力恰恰来自业务逻辑的复杂性和开发流程中的疏漏。把每一次测试当成一次对业务边界的审视你会发现很多有意思的东西。