安全测试-03-参数篡改、重放与接口滥用场景怎么发现
业务测试里,最容易被忽略的一类安全问题,不是特别“黑客感”的漏洞,而是这些更朴素的失守:
- 前端限制住的字段,后端其实照单全收
- 一次性的请求,被重复打很多次还能持续生效
- 原本只给单用户偶尔使用的接口,被脚本批量跑起来后系统完全没防护
这些问题看起来不复杂,但落到真实业务里,风险往往非常直接:
- 金额被改了
- 订单被重复提交了
- 优惠券被反复领了
- 验证码被打爆了
- 导出接口被批量刷穿了
所以如果要在安全测试里优先抓一类问题,通常会优先看这三件事:
- 参数篡改
- 请求重放
- 接口滥用
这篇文章就围绕这三类问题,讲一套更适合业务测试落地的发现方法。
一、先明确三类问题分别是什么
1. 参数篡改
本质是:
客户端传上来的参数,本来不应该被完全信任,但服务端真的信了。
常见场景:
- 金额、折扣、数量
- 角色、状态、审批结果
- 文件路径、导出范围
- 用户 ID、部门 ID、资源归属 ID
2. 请求重放
本质是:
一个原本只该生效一次,或者只该在某个时间窗内生效的请求,被重复使用了。
常见场景:
- 支付回调
- 审批动作
- 下单提交
- 领取优惠券
- 发送验证码
3. 接口滥用
本质是:
接口设计默认按“正常用户偶发使用”考虑,但没有限制住批量调用、异常频率、异常顺序和异常规模。
常见场景:
- 注册、登录、短信发送
- 查询、导出、搜索
- 批量创建、批量删除
- 上传、下载、回调
把这三类问题分开很重要。
因为虽然它们经常一起出现,但排查和修复点不完全一样。
二、哪些接口最值得优先测
如果时间有限,我优先看下面这些动作型接口:
- 下单、支付、退款、充值
- 审批、驳回、删除、封禁
- 领券、核销、积分变更
- 发送验证码、发送通知、触发任务
- 导出、下载、批量查询
- 回调、Webhook、内部运维接口
为什么这些接口优先级高?
因为它们通常同时具备下面至少一个属性:
- 能改钱
- 能改状态
- 能改权限
- 能批量消耗资源
- 能触发下游动作
只要具备这些属性,参数篡改、重放和滥用的收益就很高,风险也会很直接。
三、更常用的一套检查顺序
1. 先正常走业务链路
不要上来就乱改包。
先把业务动作正常跑一遍,明确:
- 哪个请求是真正的写操作
- 哪些参数看起来像“业务核心字段”
- 哪些头、Token、签名、时间戳在变化
例如做“领券”流程时,先记录:
- 用户点击领券时到底发了哪一个请求
- 请求体里有没有
couponId、userId、count、channel - 是否带
nonce、timestamp、sign
2. 再判断字段谁该可信,谁不该可信
这是参数篡改测试的关键。
通常会把字段先分成三类:
- 展示型字段:改了通常没意义
- 业务型字段:金额、数量、状态、角色、资源 ID
- 防护型字段:签名、时间戳、nonce、token
最值得优先试的,永远是业务型字段。
3. 再判断请求是不是天然有“一次性”要求
这一步是重放测试的关键。
如果一个请求满足下面任一条件,就应该主动怀疑它是否需要防重:
- 会扣钱
- 会改库存
- 会改状态
- 会发券
- 会触发审批
- 会触发短信或回调
4. 最后再看接口能不能被批量、异常频率、异常顺序使用
这一步是滥用测试的关键。
例如:
- 一分钟发 200 次验证码会怎样
- 同一个导出接口并发跑 30 个任务会怎样
- 同一个用户连续发 500 次搜索请求会怎样
- 正常应该“先登录再提交”的流程,如果直接跳过前置步骤会怎样
四、参数篡改最小执行骨架
如果要总结一套最小可执行方法,可以这样做。
1. 先记一张字段风险表
| 参数 | 来源 | 业务含义 | 理论上谁该决定 | 首测动作 |
|---|---|---|---|---|
amount |
请求体 | 支付金额 | 服务端订单系统 | 改小/改大 |
role |
请求体 | 用户角色 | 服务端权限系统 | 提升角色 |
status |
请求体 | 审批结果 | 服务端流程引擎 | 直接改通过 |
deptId |
请求体 | 数据范围 | 服务端数据权限 | 换部门 |
userId |
请求体 | 操作者身份 | 服务端登录态 | 换人 |
这张表非常有用。
因为很多时候你只要看一眼,就知道哪些字段不应该由前端说了算。
2. 每次只改一个关键字段
例如:
- 把
amount=100改成1 - 把
count=1改成10 - 把
status=draft改成approved - 把
role=user改成admin
一次只改一个,才能知道系统到底信了哪一个字段。
3. 同时确认最终业务结果
不能只看响应体。
要同时确认:
- 页面状态有没有变化
- 列表数据有没有变化
- 数据库或日志里有没有真实落库
- 下游动作有没有被触发
否则很容易把“接口回包松”误判成“真实漏洞”。
五、请求重放最小执行骨架
1. 先识别哪些动作应该天然防重
重点接口通常包括:
- 下单
- 支付确认
- 审批通过
- 退款提交
- 领券
- 发送验证码
2. 固定 3 组重放动作
通常每个关键接口至少做这 3 组:
- 原请求立即重复一次
- 原请求间隔几十秒再重复一次
- 复制原请求并发重复多次
这三组能快速看出:
- 有没有幂等控制
- 有没有时间窗限制
- 并发下是否会重复落库
3. 重点观察这些结果
- 是否重复创建订单
- 是否重复发券
- 是否重复扣库存
- 是否重复发送短信
- 是否重复触发回调
很多问题不是响应不对,而是下游被多次触发。
六、接口滥用最小执行骨架
接口滥用最怕测成“纯压测”,那样结论会很虚。
更倾向按业务约束去看。
1. 先问接口正常使用假设是什么
例如:
- 登录接口默认一个用户一分钟不会失败 500 次
- 验证码接口默认一个手机号一分钟不会发 30 次
- 导出接口默认一个用户不会同时导出 20 份大报表
2. 再刻意打破这个假设
例如:
- 单账号高频失败登录
- 同手机号重复发码
- 同用户并发导出
- 同资源批量刷详情
3. 观察系统有没有最基本的边界保护
至少要看:
- 频控
- 限流
- 验证码/图形码
- 幂等
- 队列削峰
- 单用户/单资源限制
如果这些都没有,接口就很容易从“正常业务能力”变成“可被脚本滥用的入口”。
七、最容易踩的几个坑
1. 只改参数,不理解参数背后的业务含义
例如把 status=approved 改成功了,问题不只是“参数可改”,更可能说明流程状态机完全没有在服务端兜住。
2. 只看接口回包,不看后续副作用
一个请求重复打两次,第二次也许回包是失败。
但如果短信已经发了两次、库存已经扣了两次,那问题依然成立。
3. 把测试环境宽松配置当成正式问题
例如测试环境关闭了签名、关闭了频控、短信走了假通道。
这种情况需要单独标注,否则优先级会失真。
4. 把接口滥用测成纯性能问题
接口滥用不是单纯看“扛不扛得住”,而是看:
- 不该被这样用时,系统有没有边界保护
- 被这样用后,会不会产生业务性损失
八、真实案例:为什么“每人限领一次”的优惠券被领了三次
场景
一个活动系统里,运营配置了一张优惠券,规则是“每个用户限领一次”。
前端页面上,用户领取成功后按钮会变灰,页面提示“已领取”。
功能测试时,这条流程表现正常。
执行
我在第一次领券时抓到了请求:
1 | POST /api/coupon/receive |
然后做了两组动作:
- 在第一次领取成功后,立即重放相同请求两次
- 再开两个并发请求同时重放
现象
接口并不是每次都返回成功。
但在最终账户里,这个用户实际拿到了 3 张券。
也就是说:
- 页面按钮置灰了
- 前端看起来拦住了
- 部分回包还提示失败
但服务端的发券动作在并发和重复请求下还是执行了多次。
排查
后面顺着日志看,问题链路很清楚:
- 服务端先查“用户是否已领券”
- 如果没有,就插入领券记录
- 但这两个动作之间没有真正的原子控制
- 并发请求同时进来时,多个请求都在“还没看到已有记录”这个窗口里通过了校验
这本质上不是前端问题,而是:
- 没有幂等令牌
- 没有唯一约束兜底
- 没有并发条件下的防重设计
修复
最后给出的修复建议分了 4 层:
- 发券动作增加幂等控制
- 数据库对“用户 + 优惠券”增加唯一约束
- 并发冲突时返回明确的“已领取”语义
- 增加自动化回归用例:
- 同一用户连续重放领券请求
- 同一用户并发重放领券请求
- 预期最终只生成一条有效领券记录
这个案例很典型地说明:
“页面按钮灰了”不代表服务端真的守住了。
九、怎么把这类问题持续沉淀下来
更合适的做法是把这三类检查固化成上线前的固定动作。
第一层:手工检查清单
高风险接口固定检查:
- 关键业务参数能不能被改
- 关键动作能不能被重复打
- 高频接口有没有最基础频控
- 批量接口有没有被异常规模调用的空间
第二层:自动化回归
把下面这些最关键的场景做成脚本:
- 重放领券/审批/下单请求
- 改金额、改数量、改状态
- 并发重放一次性动作
- 高频请求打登录、短信、导出类接口
这样才能避免系统每改一轮就把老问题重新带回来。
十、写在最后
参数篡改、重放、接口滥用之所以值得优先抓,不是因为它们听起来专业,而是因为它们离真实业务损失非常近。
很多系统安全问题,最后都能落回一句很朴素的话:
- 不该由客户端决定的,被客户端决定了
- 不该重复执行的,被重复执行了
- 不该被大规模使用的,被大规模滥用了
如果这三条边界没守住,再多的安全术语也没有太大意义。