如果你最近常刷SRC,大概会有个很直观的感受:SQL注入、XSS、文件上传这些经典入口,提交量已经卷成一片红海。同一个站点的反射型XSS,可能被十几个人反复提交,重复率极高,审核周期也长,最后评级往往还上不去。我大概从去年开始调整打法,把大部分精力压到API接口漏洞上,半年下来有效漏洞数量反而明显提升,而且出的几个高分漏洞全集中在接口鉴权和业务逻辑层面。这篇就系统聊聊我是怎么避开传统Web漏洞思路,用接口视角在SRC里拿高分的。
这篇文章适合两类人:一类是已经玩过一阵子Web渗透、想换赛道提效的朋友;另一类是对API设计有了解、但不知道从哪下手做漏洞测试的读者。我会把从资产发现、漏洞验证到报告提分的完整链路拆开讲,过程中会穿插我实际测试时的踩坑经验,尽量让你看完就能直接上手。
1. 为什么我把重心从Web页面转向API接口
1.1 传统入口的“卷”和接口侧的“空”
传统Web漏洞之所以难出成绩,不是因为它们不存在,而是因为企业防御已经把这些口子堵得差不多了。WAF规则迭代很快,参数过滤越来越严,框架本身也自带很多安全机制。你花半天找到的SQL注入点,很可能在审核那边被判定为“低危+重复”,辛苦半天就换个热心参与奖。
API接口侧的情况完全不同。很多企业的API治理还停留在“能用就行”的阶段,接口路径不统一、认证鉴权不完整、文档随意暴露、新旧版本并行,问题密度相当可观。更重要的是,大多数测试者还习惯把视角固定在“页面—参数—注入”这条老路上,能想到去系统测API的人相对少,竞争压力小很多。
我并不是说传统Web漏洞不能测,而是说在同样的时间投入下,接口漏洞的产出确定性更高。一次成功的水平越权,往往直接对应一批用户数据泄露,这种漏洞的危害认定天然高于某个反射型XSS。
1.2 SRC评分体系下的价值锚点
要理解为什么API漏洞容易拿高分,你得先理解SRC的评级逻辑。大部分平台的评级主要看三条:数据敏感程度、影响范围、利用难度。传统Web漏洞里常见的反射型XSS,数据敏感性低,影响范围通常只有攻击者自己,利用还需要诱导点击,所以很难上高危。而一个未授权接口如果直接返回了用户手机号、身份证、订单详情,数据敏感度直接拉满,影响范围可能是全量用户,这种组合在评级上几乎不可能低。
我整理了一张对比表,方便你直观感受两类漏洞在评分维度的差异:
| 维度 | 传统Web漏洞(如SQLi/XSS) | API接口漏洞(越权/未授权/逻辑) |
|---|---|---|
| 数据敏感度 | 取决于入口功能,普遍较低 | 常直连核心业务数据,天然敏感 |
| 影响范围 | 单点、单用户、需交互 | 可批量、可遍历、面向全量 |
| 利用确定性 | 依赖浏览器/环境 | 构造请求即可复现,确定性高 |
| 审核观感 | 修复成本低、容易被降级 | 危害可视、修复通常伤筋动骨 |
| 重复概率 | 极高 | 相对低 |
这也是我建议你把精力切过来的核心原因:不是传统漏洞消失了,而是API漏洞在“投入产出比”上更划算。
1.3 什么样的人适合优先走这条路
接口漏洞测试的门槛并不高,但它和传统Web渗透需要的心态不太一样。传统渗透讲究“广撒网”,拿扫描器跑一圈,看哪里的指纹有问题。接口测试更像“读代码”,你要耐得住性子去看请求、猜参数、对比响应差异。
如果你手上有基本的Burp Suite操作能力,能看懂HTTP请求结构,对JSON、Authorization头、状态码这些概念不陌生,那你就完全具备切入API漏洞挖掘的基础。真正拉开差距的是你对“业务逻辑”的理解程度——比如你在测一个订单接口时,能不能想到去改数量、改金额、跳步骤、换用户ID,这决定了你能挖到低垂果实还是深水漏洞。
2. 接口漏洞的信任边界本质:四种最容易失控的场景
2.1 API与Web页面的产品逻辑差异
很多人对API漏洞有个误解,觉得“API不就是返回JSON的URL嘛,我扫一下参数就行”。这种理解会让你错过最核心的东西。API和Web页面的本质差异在于:页面是给人用的,交互过程有层层设计——按钮、验证码、跳转、二次确认;API是给机器用的,设计目标是高效率和低冗余,直来直去,一条请求进去,一条结果出来。
正因为API追求高效,很多企业从潜意识里就把“知道接口路径”等同于“被授权使用”,好比一栋写字楼,大门安保严格,但员工侧门只要工牌样式像真的就放行。做接口漏洞测试的人,要找的就是这些“侧门”和“员工通道”。
2.2 四种边界失控形态与测试触发点
我把这些年遇到的接口问题归纳成四种典型形态,每一种对应一个明确的测试动作:
第一种:无认证访问。接口压根不校验调用者身份,任何人拿个HTTP请求就能拿到数据。测试动作很简单:把请求里的Cookie、Authorization、Token全部删掉,再看返回结果有没有变化。如果删掉凭证后数据照样返回,就是一个未授权访问漏洞。
第二种:弱认证绕过。接口检查了认证,但校验本身存在缺陷。比较常见的是JWT的alg设为none、签名密钥硬编码在前端代码里、Token校验只判断“非空”不判断“有效性”。这类问题需要你拆开令牌看算法和结构,属于高级一点的认证绕过。
第三种:无鉴权或鉴权缺失。认证和鉴权是两回事。很多接口只验证了“你是不是登录用户”,但没有验证“你有没有权限操作这个数据”。普通用户登录后直接调用管理员的删除接口,或者A用户传B用户的ID去查订单,都属于这一类,也是测试中最高频出现的越权漏洞。
第四种:参数被无条件信任。服务端完全采信客户端传上来的业务参数,金额、数量、折扣、状态、步骤全部由前端决定。你传负数就给你减钱,你传0元就0元支付,你把订单状态改成“已完成”它就真的完成。这类逻辑漏洞在金融、电商类SRC里特别常见。
2.3 先忘掉“漏洞类型”,先找“信任关系”
我个人的习惯是,测试一个接口时不会先从漏洞类型出发,而是先问三个问题:这个接口信任了什么?这个信任关系成立吗?如果我破坏这个信任关系,业务会怎样?比如一个查询接口,它信任URL里的订单ID属于当前用户——这就是信任关系;如果服务器没有验证这一点,你替换成别人的订单ID就是越权。这个思路比死记漏洞类型实用得多,因为接口形态千变万化,但信任边界失控的逻辑是共通的。
3. 实战前的资产梳理:把隐形的API接口找出来
3.1 客户端抓包:把接口清单“导”出来
接口漏洞测试的第一步永远不是猜,而是看流量。打开浏览器开发者工具的Network面板,正常登录、下单、查询一遍业务,所有前端调用的API接口路径、参数结构、请求方式就全在眼前了。这是最准、最全、零成本的接口清单。
移动端App也一样,配置好Burp Suite的代理后,把App里各个功能模块点一遍,HTTPS流量会经过Burp呈现出来。你会发现App端常常比Web端多出不少接口,尤其是上传、分享、推送这类功能,后端对App端的鉴权往往更松懈。
这里有个实操细节:抓包时别只盯着返回200的接口,404、405、500的请求同样有价值。404可能暴露了隐藏路径,405说明路径存在但方法不对,换个方法往往有惊喜,500则可能泄露内部堆栈信息。
3.2 前端JS和接口文档:还没开始测就能拿一半信息
抓完包后,第二件事是翻前端代码。现在单页应用流行,大量接口逻辑都写在JS文件里。用Burp的Target站点地图或者浏览器搜索功能,全局搜索“api”、“/v1/”、“/v2/”、“axios.post”、“fetch(”这些关键词,能快速把后端接口路径拼出一张全景图。
更省力的是找接口文档。很多企业会不小心把Swagger、OpenAPI、RAP之类的文档留在线上,路径通常是/swagger-ui.html、/api-docs、/doc.html。一旦发现Swagger文档,整个项目的接口、参数、数据模型全暴露了,后面测试基本就是照着菜单点菜。我建议把文档里出现的所有接口先保存下来,作为一份待测清单,再逐条验证。
3.3 路径规律与版本演进:把接口“推算”出来
接口的命名往往有强规律,知道一个就能顺藤摸瓜猜出一串。比如你已经知道/api/v1/users/123,那么大概率存在/api/v1/orders/123、/api/v1/payments/123;有/v1/就可能有/v2/,甚至/internal/。我会基于已知接口构造一批候选路径,然后用最小请求去验证是否存在。
版本演进是特别容易出问题的地方。很多系统升级过程中会同时保留新旧两套接口,新接口鉴权严密,但老接口可能为了兼容旧客户端而降低了校验强度。测试时多留意接口路径里的版本号,老版本接口往往是鉴权薄弱的重灾区。
提示:路径枚举时尽量用小字典、低速率,避免大量并发请求触发封禁。SRC测试规范里通常要求控制扫描强度,别把目标站点打挂了。
3.4 资产测绘与搜索:换个视角找入口
如果目标授权范围允许,还可以用网络空间测绘引擎去搜目标域名的接口特征。比如搜索title:"swagger" && domain:xxx.com,或者搜特定的接口路径特征。这种方式的优势是能发现一些不挂在主站功能下的接口,比如测试环境、灰度环境、管理后台的独立接口。
需要特别强调:不管是抓包、翻文档还是测绘,所有动作都必须在SRC授权范围内进行,仅针对允许测试的目标。永远不要对未经授权的目标做任何探测,这是底线。
4. 四类高频接口漏洞的手把手验证流程
4.1 越权(IDOR)完整验证链路
越权是我最喜欢也最推荐新人练习的接口漏洞类型,因为它的验证逻辑非常清晰。完整流程大概是:注册两个测试账号A和B,登录账号A抓取某个查询接口的请求包,找到请求里唯一标识数据的参数(通常是ID字段),把这个值改成账号B对应的值,如果响应返回了B的数据,水平越权就确认了。
有几点实操经验值得记下来。第一,ID不一定在URL里,也可能在POST的JSON体里、在请求头的X-User-ID里、甚至在文件名里。第二,响应对比不要只看状态码,还要看响应体长度和内容,有时候状态码是403,但响应体已经带出了数据。第三,如果ID是UUID格式,别急着放弃,很多接口支持批量ID也支持数组形式,或者存在一个“按条件查询”的接口,可以绕过单个ID的限制。
垂直越权的测法类似:用普通用户身份去请求管理员功能的接口,比如用户管理、配置修改、数据导出。这类接口路径往往带有admin、manage、console字样,抓包时看到就要额外留意。
4.2 未授权与鉴权缺陷
未授权测试的做法很直接:把请求里所有身份凭证字段删掉,再看返回结果。具体来说,先抓一个正常请求,记录下它的完整请求头,然后依次删除Cookie、Authorization、Token、X-Token这些字段,逐个发送看响应。
我在测试中见过最典型的情况是:接口用了两个token,请求头有个token,请求体里还带了一个user_id。后端只校验了请求头token的有效性,但业务逻辑用的是请求体里的user_id,于是你把user_id改成别人的,就成了越权;把两个token都删掉,如果接口还能返回数据,就成了未授权。
GraphQL接口也要单独留意。很多GraphQL服务开启了Introspection查询,你可以发一个查询请求把整个Schema拉出来,里面包含所有查询、变更和数据类型。更常见的问题是GraphQL通常只有一个端点,但每个查询的鉴权强度不同,有的查询甚至完全没有校验。测试时逐个查看Schema里的字段,你会发现不少只给内部使用、但没有任何保护的数据查询入口。
4.3 参数篡改与业务逻辑边界
业务逻辑漏洞测试和纯粹的安全漏洞测试不太一样,它需要你理解业务流程的“正确顺序”和“预期值”。我通常关注四类位置:金额类参数、数量类参数、状态类参数、重复操作类参数。
金额类开发最典型的场景是电商支付。正常下单时,请求里带了商品总价,你把金额改成负数或0,看服务端是否重新计算。很多后端信任前端传的金额字段,导致“0元购”或“倒扣金额”的出现。数量类问题常见于购物车、库存、优惠券场景,你把购买数量改成负数或超大值,看最终订单金额如何变化。
状态类参数适合有流程编排的系统,比如订单状态从“待支付”直接改成“已完成”,或者工单从“待审核”改成“已驳回”。如果服务端没校验状态流转的合法性,就能绕过中间的审核、支付环节。重复操作类的经典场景是优惠券/兑换码/抽奖次数,把同一个请求重复发送,看能不能无限次使用。这里可以用Burp的Repeater手动重放,也可以用脚本并发验证,但要注意控制频率,避免对业务产生实质影响。
注意:逻辑类漏洞验证时,尽量使用自己的测试账号和数据,不要动真实用户的数据,更不要把漏洞直接“玩到底”,确认能产生影响就停。
4.4 信息泄露与调试残留
接口信息泄露往往被忽视,但它很适合拿来出报告,因为证据清晰、危害直接。常见表现形式有三类:接口报错时返回堆栈信息,暴露出后端语言、框架、路径、数据库结构;接口返回了本不该返回的字段,比如用户详情里带了内部员工编号、密码哈希、手机号;调试接口或测试接口残留,比如/debug、/actuator、/health等路径可以直接访问,暴露运行时配置和内部状态。
这类漏洞的挖掘方式其实很简单:在正常接口测试中多留意“异常响应”和“多余字段”。看到一个500错误返回了长长的Java异常栈,先截图保存,再去验证它泄露的信息是否敏感;看到接口返回字段里有internal、password、phone之类的key,先确认这些字段在页面上是否展示,如果不展示但接口返回了,就是信息泄露。
4.5 自动化辅助验证的思路
接口一多,手动测就忙不过来,这时可以用脚本做半自动化验证。我常用的模式是用Python的requests库写一个模板脚本,读取目标接口的请求包,自动替换ID、删减凭证、比对响应长度和内容,把“变化”筛出来人工复核。
以越权批量验证为例,脚本逻辑大概是:发送正常请求记录基准响应体,把ID替换成目标值列表循环发送,筛选出响应体长度或关键字段与基准不一致的结果。这种脚本写起来不难,但能显著提升接口测试效率,尤其是面对几十个同类接口时。
import requests # 仅供SRC授权范围内使用,自行替换目标与Cookie base_url = "https://target.example.com/api/v1/order/" headers = {"Cookie": "session=your_test_session"} def fetch_order(order_id: str): resp = requests.get(base_url + order_id, headers=headers, timeout=10) return resp.status_code, resp.text # 基准请求 base_status, base_body = fetch_order("100001") # 遍历候选ID for oid in ["100002", "100003", "100004"]: status, body = fetch_order(oid) if body != base_body and status == 200: print(f"[+] 疑似越权: order_id={oid}, status={status}, length={len(body)}")自动化结果出来之后,人工复核是必须的。脚本只能帮你缩小范围,最终的漏洞确认和危害评估还是要靠人去判断。
5. 报告阶段:如何让你的漏洞在SRC里拿到高分
5.1 评级背后真正在看什么
同样的越权漏洞,有的人报上去是高危,有的人报上去只有中危,差距往往不在漏洞本身,而在你对“危害”的描述。SRC审核员判断一个漏洞是否够高,核心就一句话:这个漏洞能被利用到多大范围、造成多大影响。
举个例子。你发现一个订单查询接口越权,如果只写“我能查看任意订单”,这充其量是中危。但如果你在这个基础上进一步验证:订单ID可以从1遍历到100000,响应包含收件人姓名、电话、地址,这意味着攻击者可以批量拉取全量订单数据——危害等级自然就上去了。高分报告的本质是把你验证过的“最坏影响”完整呈现出来,而不是简单描述“接口存在越权”。
5.2 报告结构模板与写作要点
我提交报告的习惯是固定一套结构,审核员看得舒服,自己也不容易漏信息:
- 标题:一句话说清楚“哪个接口+什么漏洞+能做什么”。比如“某平台订单详情接口存在水平越权,可遍历查看任意用户订单”,比“订单接口越权”要清楚得多。
- 影响范围:受影响的功能模块、接口路径、漏洞类型。
- 复现步骤:按顺序写清楚每一步操作,包括完整请求包、替换的参数、返回的关键数据。这一步一定要配请求和响应截图,图里对敏感字段打码,但保留足够的证据性。
- 危害论证:说明攻击者实际可以利用的路径——是单条数据泄露还是可批量遍历,涉及哪些敏感信息,可能造成什么业务后果。
- 修复建议:给出至少两条可落地的建议,比如“服务端校验当前用户是否拥有该订单的访问权限,不要仅凭前端传入ID”。
5.3 扣分点自查清单
我踩过很多次扣分的坑,总结成一张自查清单,提交前过一遍,基本能避免无谓的降级:
| 检查项 | 常见问题 | 自查要点 |
|---|---|---|
| 标题 | 模糊、没写接口 | 标题是否包含接口名+漏洞类型+影响 |
| 复现 | 截图不完整 | 请求包、响应包、时间标记是否齐全 |
| 证据 | 敏感字段不打码 | 打码但保留关键信息,避免泄露真实数据 |
| 危害 | 夸大或不足 | 是否与实际验证结果一致 |
| 修复 | 空话套话 | 是否针对具体漏洞给出操作级建议 |
| 范围 | 越权操作未收敛 | 是否只验证到“可证明”程度就停止 |
5.4 提升评分的几个加分细节
最后说几个能让报告更专业的小细节。第一,复现步骤里加上时间戳和域名信息,审核员会更快确认环境。第二,危害论证中尽量量化——“可遍历10000个订单”比“可查看他人订单”有说服力得多。第三,如果漏洞涉及多种请求方式或多个接口,一次性把同类问题汇总在一个报告里,通常比拆成好几个低危报告更受认可。
最后想说的话
接口漏洞挖掘这条路,门户不高,但需要持续的“接口敏感度”,也就是你看到一个接口时能本能地想到:这个参数我能不能改成别人的?这个凭证我删掉会怎样?这个金额字段服务端到底校验了没有?这种敏感度要靠大量阅读请求和总结规律来养,做得多了,你会发现在别人眼里平平无奇的接口,在你这里全是线索。
我自己做下来最大的体会是:接口漏洞不是靠扫描器扫出来的,而是靠一层层梳理信任关系、一次次构造边界请求试出来的。SRC这条路没有捷径,但选对赛道、用好方法,至少不会让你辛辛苦苦提交的报告总在低危边缘徘徊。