挖逻辑漏洞这件事,说难也难,说简单也简单。难的地方在于它没有一堆现成的 payload 模板可以照抄,你没法拿个字典跑一遍就等结果;简单的地方在于,绝大多数逻辑缺陷都藏在业务流程最"理所当然"的地方——下单、领券、改密码、看订单,这些每天被用户点几千遍的功能,恰恰是最容易被开发和测试双方同时忽略的角落。这篇文章我把"漏洞挖掘的三种技术"和"一次授权范围内的逻辑漏洞实战"揉在一起讲,因为这两件事本来就是一回事的两面:技术路线决定了你能看到多宽,对业务的理解决定了你能挖多深。内容适合刚入门、手里只有一台笔记本和一份明确授权测试范围的新手,也适合做了几年常规测试、一碰到业务逻辑就不知道从哪下手的朋友。
1. 三种漏洞挖掘技术,先搞清楚各自的地盘
1.1 黑盒、灰盒、白盒的真实边界
行业里讲"三种技术",一般指的是黑盒测试、灰盒测试、白盒测试,划分依据很简单——你手上掌握多少内部信息。
黑盒测试是只给一个入口地址,不知道源码、不知道架构、不知道数据库,完全站在外部使用者视角去试。优点是贴近真实攻击者的视角,缺点是效率低、覆盖面靠运气、容易漏掉只在特定条件下才触发的分支。新手最容易犯的错就是以为黑盒就是"拿工具扫一遍",实际上扫描器只能覆盖已知模式的表层问题,对业务逻辑几乎无能为力。
白盒测试是拿到源码做代码审计,从数据流和控制流去找污点传播路径。它的效率极高,一个中等规模的 Web 项目,熟悉框架的人两三天就能把危险函数过一遍。但白盒的门槛在于你得读得懂框架的封装,很多人审计的时候只盯着eval、system这类显眼函数,反而漏掉了业务层里"判断条件写反了"这种更致命的问题。
灰盒测试是两者之间,通常表现为:你有一个正常账号,能看到部分接口和参数,但看不到源码。这是绝大多数授权测试场景的真实状态——给你一个测试账号和一份范围说明,剩下的全靠自己摸。逻辑漏洞挖掘基本都发生在灰盒这个区间里,因为你必须"以合法用户的身份,做不合法的事",才能触发那些权限判断上的疏漏。
我把三者的取舍整理成一张表,实际项目里我是按这张表决定投入比例的:
| 技术路线 | 信息掌握程度 | 典型产出 | 时间成本 | 适合阶段 |
|---|---|---|---|---|
| 黑盒 | 仅入口 | 配置缺陷、暴露面、通用漏洞 | 低 | 项目起步,快速摸底 |
| 灰盒 | 账号 + 部分接口 | 越权、支付逻辑、状态机缺陷 | 中 | 主力投入区间 |
| 白盒 | 完整源码 | 硬编码、注入点、加密误用 | 高 | 有源码时的加速手段 |
这张表的用法不是"选一个",而是按顺序叠加。我通常的做法是:先花半天黑盒把资产和入口摸清楚,再用灰盒在核心业务链路上做深度测试,如果同时能拿到源码,就用白盒去验证灰盒阶段的猜测,把"疑似"变成"确认"。三种技术不是三选一,是一条流水线上的三道工序。
1.2 为什么新手的第一站应该是逻辑漏洞
很多人入门的时候直奔注入和反序列化,觉得那才叫"技术"。我的看法相反:逻辑漏洞是新手性价比最高的切入点,理由有三个。
第一,它对工具依赖极低。你只需要一个抓包代理工具(我习惯用 Burp Suite,社区版够用)、一个浏览器、两三个自己注册的账号,就能开工。不需要配复杂的漏洞环境,不需要去啃一堆利用链。
第二,它考验的是思维而不是记忆。注入有固定的探测手法,逻辑漏洞没有。你得站在产品经理的角度问自己:"这个功能设计的时候,默认用户会怎么操作?如果我不这么操作呢?"这种"反着想"的能力,一旦练出来,迁移到任何业务场景都能用。
第三,它的报告更容易被认可。一个能说清楚"我怎么用 1 块钱买到了 1000 块的会员"的复现过程,比一个只写了"此处存在注入"的截图有说服力得多。审核的人看的是影响,而逻辑漏洞的影响往往直接对应钱和权限。
当然,前提得说清楚:所有测试必须在你自己的环境、或者有明确书面授权的测试范围内进行。自己搭靶场、自己写 demo、参加公开的授权测试项目,这三条路随便走,其他的一律不碰。这不是套话,这是这个领域能不能长期做下去的分界线。
1.3 一次授权测试的整体节奏安排
我习惯把一次完整的测试拆成四段,时间分配大概是 2:5:2:1。
摸底(20%):收集子域、接口、参数、角色,画一张业务地图。这一步偷懒,后面全是瞎猜。
验证(50%):按业务链路逐条走,每个功能点问三个问题——谁能访问、能访问到什么程度、能改什么。
复现(20%):把疑似问题用最小步骤稳定复现三遍,排除偶然因素(缓存、异步、前端限制)。
成文(10%):写报告。这部分很多人敷衍,其实它决定了你的发现能不能被认定为有效。
这个比例不是死的,遇到支付类核心链路,验证阶段的占比我会拉到 70%。因为支付链路的每一个参数背后都对应真金白银,值得反复推敲。
2. 逻辑漏洞到底在挖什么
2.1 它和常规漏洞的本质差异
常规漏洞(注入、跨站脚本、文件包含)的共同点是:输入的数据被当成了代码执行。所以防御思路很统一——过滤、转义、参数化。逻辑漏洞不一样,它的输入数据完全合法,格式正确、长度合规、字符集干净,问题出在服务端对这个合法数据的处理顺序和判断条件上。
举个生活化的类比。银行柜台取钱,正常流程是:查余额 → 验证密码 → 扣款 → 出钞。如果柜员的操作顺序变成:查余额 → 扣款 → 验证密码,那么只要在验证那一步卡住(比如故意输错),钱可能已经扣了但没出,或者反过来——在某些实现里,验证失败后事务没有回滚,钱没扣但钞出了。数据本身没毛病,流程顺序出了毛病。
这就是逻辑漏洞的核心特征:它不是"坏数据",是"坏流程"。所以扫描器基本扫不出来,因为扫描器只会试各种畸形输入,它不知道你的业务应该是什么顺序。
2.2 六类高频逻辑缺陷速查
我把这些年遇到过的逻辑问题归成六类,实际项目里按这个清单过一遍,命中率相当高:
| 类别 | 核心问题 | 典型表现 |
|---|---|---|
| 越权访问 | 只校验"登录了"不校验"是不是你的" | 改 ID 看到别人数据 |
| 支付篡改 | 金额/数量由客户端决定 | 改价、负数、0 元单 |
| 状态机缺陷 | 状态可以跳变或回退 | 未付款直接变已发货 |
| 验证码缺陷 | 校验与业务分离 | 复用、回显、可爆破 |
| 并发问题 | 检查与使用之间存在时间窗 | 一券多用、超发 |
| 流程绕过 | 关键步骤可跳过 | 跳过实名、跳过风控 |
逐条展开说。
越权访问是最常见也最好上手的。它分两种:水平越权是同级用户之间互相看,A 能看到 B 的订单;垂直越权是低权限干高权限的事,普通用户调到了管理员接口。判断方法很朴素——准备两个账号,用 A 的身份去请求 B 的资源标识。
支付篡改的关键在于搞清楚"钱是谁算的"。如果下单接口的请求体里带着price、amount、total这类字段,而服务端直接拿来用,那就有得聊了。除了改小,还要试负数(可能导致余额增加)、试超大值(可能整数溢出或触发特殊分支)、试精度(0.01 和 0.001 的舍入差异)。
状态机缺陷需要你把订单、工单、审批这些有状态的实体画成一张状态转移图,然后问:能不能从"待支付"直接跳到"已完成"?能不能把"已退款"改回"待发货"?退款之后商品还能不能用?
验证码缺陷的检查点比较固定:验证码和手机号/邮箱有没有绑定关系、验证码在响应包里有没有回显、验证成功后有没有立即失效、有没有次数限制和时间窗口。
并发问题是最容易被忽略的一类。服务端的典型写法是"先查再改":查一下优惠券还没用 → 用掉 → 更新状态。如果两个请求同时进来,都查到"还没用",就都通过了。这类问题单发一百次都正常,必须用并发才能触发。
流程绕过指的是关键校验步骤可以被跳过。比如实名认证是一个独立页面,那我直接请求认证后的接口会怎样?比如风控是在前端做的判断,那把前端判断去掉会怎样?
2.3 从业务流程倒推测试点的方法
我给新手的一个练习方法叫"三问法"。拿到任何一个功能,问三个问题:
第一问:这个功能正常应该发生什么?把预期结果写下来。比如"领券"应该是:用户点一次 → 券进入账户 → 该券状态变为已领取 → 不能再领。
第二问:如果我偏离正常路径,服务端会不会发现?比如我不点按钮直接发请求、我点两次、我改一下参数、我换一个账号的标识。
第三问:出问题的话,损失落在谁头上?这个问题决定了漏洞等级。能看到别人的昵称,和能看到别人的身份证号,严重程度差着数量级;能改自己的余额,和能改别人的余额,也是两回事。
这三问不需要任何工具,拿张纸就能做。我经常在地铁上拿着手机把某个 App 的核心流程走一遍,边走在备忘录里记"这里如果换个 ID 会怎样"。很多时候灵感就是这么来的。
3. 一次授权测试的完整实操记录
下面这部分我按真实项目的推进顺序写,涉及具体系统的部分全部做了脱敏,只保留方法论和可复用的思路。你完全可以照着在自己搭的靶场里跑一遍。
3.1 信息收集:把攻击面画成一张图
信息收集不是"把能扫的都扫一遍",那是体力活。我的目标是产出一张带角色标注的接口地图。
第一步,注册三种身份的账号:普通用户、有部分权限的用户(比如商家、企业成员)、管理员(如果测试范围允许提供)。这三个账号是你的"坐标系",后面所有越权测试都靠它们做对照。
第二步,打开抓包代理,把每条业务线走一遍,重点关注四类接口:带数字 ID 的、带用户标识的、带金额的、带状态字段的。这四类接口出问题的概率远高于其他。
第三步,把接口整理成表,我通常这么记:
| 接口用途 | 方法 | 关键参数 | 身份来源 | 风险点 |
|---|---|---|---|---|
| 查看订单详情 | GET | order_id | 会话 Cookie | 能否换 order_id |
| 提交订单 | POST | sku_id, quantity, price | 请求体 | price 是否可改 |
| 领取优惠券 | POST | coupon_id | 请求体 | 能否重复领 |
| 修改资料 | POST | user_id, phone | 请求体 | user_id 是否可信 |
这张表做出来,测试路线就清楚了。重点看"身份来源"这一列——如果身份标识来自请求体而不是会话,那几乎一定有文章可做,因为请求体是用户可以完全控制的。
提示:信息收集阶段一定要克制。不要对生产环境做全量目录扫描,不要爬取非授权路径,不要批量请求。授权范围通常写得清楚,超出范围的行为,哪怕技术上是"顺手",也可能让整个项目作废。
3.2 账号矩阵与越权验证
越权验证的核心动作只有一个:交换身份标识,观察响应差异。
具体做法是,用 A 账号登录,抓到 A 查看自己订单的请求,记录下order_id=10001;再用 B 账号登录,抓到 B 的order_id=10002。然后拿 A 的会话去请求 10002。这时候响应有几种可能,含义完全不同,必须区分清楚:
| 响应情况 | 含义 | 结论 |
|---|---|---|
| 403 / 401 | 服务端做了归属校验 | 正常,继续找别的点 |
| 200 且返回 B 的完整数据 | 水平越权成立 | 高危,立即记录 |
| 200 但返回空对象或报"无权"文案 | 前后端双校验 | 正常 |
| 302 跳转到登录页 | 会话或 CSRF 校验 | 需要进一步看跳转逻辑 |
| 200 返回 A 自己的数据 | 服务端用了会话身份忽略参数 | 正常,参数是装饰性的 |
这里有个容易踩的坑:不要只看 HTTP 状态码。很多系统的错误处理做得"很温柔",任何异常都返回 200,然后在 JSON 里塞个{"code": 500, "msg": "参数错误"}。所以判断依据必须是响应体的实际内容,而不是状态码。
另外,数字 ID 不是唯一的越权入口。有些系统用 UUID,看起来不可猜,但如果你在别的接口(比如分享链接、消息通知、导出文件)里能拿到别人的 UUID,照样可以横向打。所以我的习惯是:任何地方出现的资源标识都记下来,不管它看起来多随机。
垂直越权更值得花时间。做法是拿低权限账号的会话,去请求高权限才有的接口。这些接口从哪里来?三个来源:管理后台的前端静态文件里、接口文档里、以及你自己的高权限账号的操作记录里。如果测试范围里包含管理员账号,那最省事的办法就是用管理员账号把后台点一遍,抓下所有请求,然后换成普通账号的会话重放。
这一步的注意事项是:只读操作优先。删、改、批量操作这类接口,即使越权成功也不要真执行,用最小的、可回滚的方式验证存在性即可。比如把删除接口的目标 ID 改成一个不存在的值,如果返回"目标不存在"而不是"无权限",就说明权限校验这一层被绕过了,结论已经足够。
3.3 金额与数量:支付链路里的经典陷阱
支付链路是逻辑漏洞的富矿,因为它同时具备三个要素:有明确的数值、有状态流转、有真实的利益驱动。
我先说一个通用的排查顺序,从上到下依次验证:
第一层:价格是不是前端说了算。下单请求里如果有price、unit_price、amount这类字段,先原样改成一个明显不合理的值。如果下单成功且订单金额跟着变了,问题成立。如果订单金额没变,说明服务端有重算,这层安全。
第二层:数量和金额的联动。把quantity改成负数,观察总价。很多系统用单价 × 数量算总价,负数乘出来是负值,如果后续还有余额扣减逻辑,可能变成"下单反而加钱"。同时试quantity=0、quantity=0.5、超大整数(999999999999,看是否有溢出或截断)。
第三层:优惠券的叠加与复用。检查点是:同一张券能不能在同一个订单里用两次、多张券能不能叠加、券的适用范围是不是只在前端校验、券用过之后状态有没有真正落库。这一层的经典问题是并发,下面单独讲。
第四层:退款与逆向流程。申请退款时,退款金额是自己填的还是系统算的?如果可填,能不能填得比实付多?部分退款之后,订单状态会不会变回"待发货"从而可以再次发货?
第五层:货币与单位的边界。如果系统支持多币种或多单位,试试在切换的地方做手脚,比如用低汇率币种下单、用"分"和"元"混淆的字段。
注意:金额相关的测试一定要用自己注册的测试账号、在授权的测试环境里做,并且严格控制次数。不要产生真实的资金流动,不要对生产订单做批量操作。验证"存在性"就够,不需要把整个链路跑通。
我踩过的一个坑值得说一下。早期我做支付测试,只关注请求体里的显式金额字段,漏掉了运费。有次一个项目,商品价格服务端重算了,看起来很安全,但运费是前端传的,而且运费可以填负数。于是"商品 100 元 + 运费 -100 元 = 0 元"的订单就成立了。这个教训让我后来的检查清单里永久加了一条:把所有参与金额计算的字段都列出来,一个都不能少,包括运费、税费、服务费、折扣、积分抵扣。
3.4 验证码与密码重置的状态管理
这两块放在一起讲,因为它们的问题本质相同:服务端没有把"凭证"和"主体"绑在一起。
验证码这块,我按五个检查点走:
- 绑定关系:给手机号 A 发验证码,然后拿这个验证码去验证手机号 B,能不能通过?如果通过,说明验证码没有和手机号绑定,是全局有效的。
- 复用性:同一个验证码连续提交两次,第二次是否还能通过?正确做法是验证成功后立即失效。
- 生命周期:验证码有没有过期时间?如果不填或者填一个很久以前的,是否仍然有效?
- 回显:响应包里有没有把验证码带回来?这个听起来低级,但真实项目里因为调试代码没删导致回显的情况并不少见。
- 频率限制:连续请求会不会被限制?限制是按手机号还是按 IP?如果只按 IP,换个出口就绕过了;如果只按手机号,那可以遍历手机号。
密码重置的流程更值得拆。一个完整的重置流程通常是:输入手机号 → 收验证码 → 校验 → 设置新密码。这四步里每一步都可能出问题:
第一步,输入手机号的时候,服务端返回的信息有没有差异?如果"该手机号未注册"和"验证码已发送"返回不同,就存在用户枚举。
第二步,校验验证码的接口,除了验证码之外还带了什么参数?如果带了手机号,那这个手机号是不是可以改?改了之后,验证码还能不能用?
第三步,校验通过后,服务端是返回一个一次性的重置凭证,还是直接允许设置密码?如果是前者,这个凭证能不能被猜测、能不能重复使用、有没有和用户绑定?
第四步,设置新密码的接口,能不能直接调用而不经过前面的步骤?这是最容易被忽略的——很多人只测了正常流程,没测"直接跳到第四步"。
我做过的一个练习项目里就出现过这种情况:重置流程的前三步都做得很严,但第四步的接口只校验了会话,而会话在第一步输入手机号的时候就已经建立了。也就是说,只要随便输入一个手机号触发第一步,拿到会话,就可以直接调第四步给自己想改的账号设密码——当然,前提是第四步的请求体里带着目标账号标识。这个问题的本质就是流程的原子性被破坏了,四个步骤本该是一个不可分割的整体,实际却可以单独调用。
3.5 并发与条件竞争
这类问题的技术门槛稍微高一点,但原理非常简单:"检查"和"使用"之间有时间差。
服务端的典型代码逻辑是三步:查询余额/库存/券状态 → 判断是否满足条件 → 扣减。如果两个请求几乎同时到达,都执行了第一步,都看到"满足条件",那就都往下走了。
怎么发现这类问题?我给你一个判断线索:凡是涉及"只能用一次"的资源,都值得试一试并发。优惠券、积分、余额、库存、抽奖次数、签到、邀请奖励,全是这个范畴。
测试方法是用脚本同时发 N 个请求,观察最终结果。这里要注意几个实操细节:
- N 不要太大。50 到 100 个并发足够暴露问题,上千个并发那不是测试,那是压测,会影响业务。
- 请求要在同一时刻发出。用多线程加同步屏障,让所有线程准备好后一起放行,而不是循环发。
- 观察的是最终状态,不是单次响应。很多时候每个请求的响应都是"成功",但账户里只多了一张券,那说明服务端有锁;如果多出了好几张,问题就成立。
- 注意重试机制。有些系统有幂等设计,重复请求会返回相同结果,这种情况要多试几个不同的资源 ID。
并发问题的等级判定有个讲究:如果只是"多领了一张券",可能算中低危;如果涉及余额、库存这种能直接变现的,那等级就上去了。写报告的时候要把"能重复多少次"和"每次的收益"量化出来,比如"单账号可重复领取 20 次,每次面值 50 元",这样影响才具体。
3.6 把发现写成一份能通过审核的报告
技术再好,报告写不清楚,等于白干。我见过太多"截图很炫、结论很虚"的报告,审核的人看完不知道该不该认。
一份合格的逻辑漏洞报告,我认为必须包含五块内容:
标题要具体。"某系统存在逻辑漏洞"这种标题等于没写。应该是"订单提交接口价格参数可篡改导致任意金额下单"这种,一看就知道问题在哪。
前置条件要写清楚。需要几个账号、需要什么权限、需要什么状态。这决定了别人能不能复现。
复现步骤要能一步步跟着做。我通常写成编号列表,每步只做一件事,配上请求和响应的关键片段。请求里把 Cookie、Token 打码,但保留结构和参数名。
影响要量化。不要写"可能导致经济损失",要写"任意登录用户可将 1000 元商品以 0.01 元下单,且订单正常进入发货流程"。前者是猜测,后者是事实。
修复建议要给到点子上。不要写"加强校验",要写"订单金额应由服务端根据商品 ID 重新计算,忽略客户端传入的价格字段;同时对数量做正整数范围和上限校验"。这条建议是给开发看的,不是给领导看的。
还有一个细节:复现步骤要控制在最短路径。如果你花了十步才触发,先想想有没有三步就能触发的路径。审核的人时间有限,步骤越短,认定概率越高。
4. 常见问题与排查技巧实录
4.1 十个高频疑问的直给答案
问:改了参数但页面没变化,是不是就没漏洞?不一定。要区分是"前端渲染没变"还是"后端数据没变"。最可靠的办法是改完之后重新拉一次详情接口,看服务端返回的真实数据。很多前端做了乐观更新,界面看着没变,数据库里已经变了。
问:接口返回 403 就一定是安全的?不一定。要看这个 403 是在网关层、应用层还是业务层返回的。有些系统网关拦了一批接口,但内部服务之间互相调用的时候不走网关,如果你能找到内部调用的入口(比如某个代理接口),可能就绕过去了。
问:越权测试必须用两个真实账号吗?最好用两个自己注册的账号,这样数据可控、不涉及他人信息。如果范围只给了一个账号,那就找那些资源 ID 可枚举的接口,用自己账号的 ID 加一减一去试,观察返回是"无权限"还是"不存在"——这两种响应的差异本身就是信息泄露。
问:并发测试把业务搞挂了怎么办?控制并发数,选低峰时段,测完立刻停。我个人的底线是:并发数不超过 100,持续时间不超过 10 秒,绝不针对下单、支付这类会锁库存的接口做长时间压测。
问:怎么判断一个参数是不是"装饰性"的?把它改成一个完全不存在的值,如果业务照常进行,说明这个参数根本没被使用;如果报错,说明被使用了。再改成一个合法的其他值,看结果是否跟着变。
问:为什么我扫不出东西,别人一挖一个准?大概率是信息收集做得不够。别人知道这个系统有几个子系统、几套账号体系、哪些接口是给 App 用的、哪些是给后台用的。你只看到一个登录页,当然没得挖。
问:逻辑漏洞有没有自动化工具?有辅助工具,但没有能替代思考的工具。工具能帮你做的是:批量重放、参数变异、并发发起、响应比对。判断"这个差异意味着什么"还得靠人。
问:报告被判定为"不予认可"怎么办?先看审核意见,通常是三种原因:无法复现、影响不足、属于已知设计。针对第一种,补充更详细的环境说明;第二种,把影响量化;第三种,找找有没有绕过这个"设计"的路径。
问:怎么避免测试影响到真实用户?三条:只用自己注册的账号、只操作自己产生的数据、涉及写操作的接口用不存在或非法 ID 验证存在性而不是真删真改。
问:新手应该先学什么?HTTP 协议、抓包工具的基本用法、一门脚本语言(Python 够用)。这三样扎实了,剩下的都是在这之上做加法。
4.2 我的排查顺序与工具组合
实际项目里,我有一套固定的排查顺序,从成本最低的开始:
第一步,人工走查。不开工具,就用浏览器把核心流程点一遍,边点边在纸上画流程图。这一步能发现 30% 的问题,因为它让你理解业务。
第二步,抓包比对。同样是点一遍流程,这次开着代理,把所有请求存下来。重点看请求体里有哪些字段是"我传的"而不是"系统给的"。
第三步,参数变异。对每个可疑字段做增删改:删掉、置空、改成极端值、改成其他账号的值。
第四步,并发验证。针对"一次性资源"做并发测试。
第五步,脚本批量化。当确认某类问题存在后,写脚本扩大验证范围,比如批量测试所有带 ID 的接口是否存在越权。
工具方面,我的组合很朴素:抓包代理工具负责拦截和重放,浏览器开发者工具负责看前端逻辑和存储,一个 Python 脚本负责并发和批处理,一个记事本负责记录。真的不需要太多花哨的东西,工具越多越容易陷入"配置工具"的自我安慰。
提示:所有工具都只在你拥有或获授权的环境中使用。工具本身是中性的,用它做什么决定了性质。
4.3 几个容易被误判为漏洞的现象
这块内容很少有教程讲,但特别重要,因为它直接关系到你的报告质量。
前端限制不等于漏洞。按钮置灰、输入框限制长度、下拉框只有几个选项,这些都可以用开发者工具改掉。但"能改掉前端限制"本身不是漏洞,只有当改掉之后服务端接受了非法数据,才是漏洞。我见过太多人拿着"我把 disabled 属性删了"的截图说发现了漏洞,这种报告基本会被打回。
报错信息不等于漏洞。页面报了个数据库错误,看起来吓人,但如果只暴露了表名而没有进一步利用路径,通常只能算低危信息泄露。要不要报?可以报,但等级别往高了写。
返回了别人的昵称不等于高危。判断影响要看字段敏感度。昵称、头像这类公开信息,就算越权拿到了,影响也有限。手机号、身份证、地址、订单详情,这些才是需要重点关注的。写报告时把"泄露了哪些字段"列清楚,比笼统说"泄露用户信息"有说服力得多。
能重复提交不等于漏洞。有些系统对重复提交做了幂等处理,你提交十次,结果还是一条记录,这是正常设计。只有当重复提交产生了多次实际效果(多张券、多笔订单、多次扣款),才是问题。
自己改自己的数据不等于越权。能修改自己的资料是正常功能。越权的关键是"跨主体",改别人的才算。
5. 给新手的一条可执行路线
5.1 三个月,从零到能独立完成一次测试
我把入门路线拆成十二周,每周投入十小时左右,能走完。
第 1-2 周:基础。HTTP 请求响应结构、常见状态码、Cookie 和 Session 的区别、同源策略。这些不用背,边抓包边看,两三天就有感觉。同期把抓包工具装好,学会拦截、改包、重放这三个动作。
第 3-4 周:靶场。自己搭一个简单的 demo 系统,就三个功能:登录、下单、查看订单。然后亲手在里面写出三个漏洞:越权查看、价格篡改、验证码复用。写出来之后你才知道防御该怎么做,这个反向理解的过程非常值钱。
第 5-6 周:流程分析。找五个自己常用的网站或 App,不开工具,纯人工把注册、登录、下单、退款、改密码这几条流程画成图。画完之后,在每个节点旁边标注"这里如果换个身份会怎样"。
第 7-9 周:实战练习。在有明确授权的公开测试项目里挑一个范围清晰的目标,完整走一遍:信息收集、接口梳理、越权验证、支付测试、并发测试。不求挖到东西,求流程走通。
第 10-11 周:报告。把前面的发现写成正式报告,找有经验的人帮你挑毛病。这一步的收获往往比挖洞本身大。
第 12 周:复盘。把这三个月所有"我以为有问题但其实不是"的案例整理成自己的清单。这份清单会跟着你很多年。
5.2 几条我认为不能碰的线
技术上可以做的事,和法律上允许做的事,是两回事。这个领域尤其如此。
只在自己拥有产权的系统、自己搭建的环境、或者有明确书面授权的项目里做测试。授权范围要看清楚,写了哪些域名、哪些功能、哪些时间段,超出的部分一律不碰。测试过程中产生的数据要及时清理,不要留存他人的任何信息。发现问题的第一时间按约定渠道上报,不要公开、不要传播、不要拿来当谈资。
还有一条更实际的建议:不要为了数量而堆报告。低质量的报告多了,会消耗审核方的信任,也会让你自己养成"差不多就行"的习惯。一份说清楚、能复现、影响明确的中危,价值远高于十份语焉不详的高危。
我自己这些年最大的体会是:逻辑漏洞挖到后面,拼的不是技术,是对业务的理解深度。你能想到产品经理没想到的那条路径,你就能发现别人发现不了的问题。而这个能力,只能靠一个一个功能点老老实实走、一个一个流程反反复复推演,慢慢磨出来。工具会更新,框架会换代,但"站在设计者的反面想问题"这个习惯,一直有效。