文章总结: 本文系统讲解API重放攻击原理与防护。核心问题是服务器只验证请求合法性而未验证请求是否已使用过,HTTPS和签名均不能单独防重放。高危场景包括支付、转账、优惠券等。防御方案为nonce唯一编号、timestamp时间窗口、IdempotencyKey幂等键,并建议组合使用nonce加timestamp加签名加服务端去重。文章还提供测试判断方法和开发检查清单,可操作性强。 综合评分: 85 文章分类: 应用安全,安全开发,安全测试
API 重放攻击:同一个请求为什么”再发一次”,业务就又执行了一遍?
原创
小新 小新
小新的安全运营笔记
2026年9月14日 08:00 北京
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
一、先讲一个很容易遇到的场景
假设你正在做一个电商系统。用户点击”立即支付”后,前端向后端发送:
POST /api/pay
{"orderId":"10086","amount":99.00}
后端验证登录状态、订单归属、金额都没问题,于是扣款并把订单改成”已支付”。
问题来了:如果攻击者把这条合法请求抓下来,再原封不动地发送一次呢?
如果后端只是判断”Token 有效、订单存在、用户有权限”,第二次请求也可能再次进入支付逻辑。
这就是 API 重放攻击(Replay Attack):攻击者不一定需要修改请求,只需要把一条之前合法、有效的请求,在不应该再次执行的时候重新发送。
OWASP 将这种问题归入消息重放风险,并建议使用 nonce、时间限制等机制阻止旧消息再次使用。
二、API 重放攻击到底是怎么发生的?
核心其实只有一句话:服务器只验证”这个请求是否合法”,却没有验证”这个请求是不是已经被使用过”。
一个典型过程可以理解成:
① 用户正常发起请求
↓
② 攻击者获取完整请求
↓
③ 第一次请求正常成功
↓
④ 攻击者再次发送相同请求
↓
⑤ 服务端再次执行
这里最容易产生误区:HTTPS 并不能单独解决重放问题。
HTTPS 主要保护传输过程中的机密性和完整性;如果攻击者已经在客户端、代理、日志、被控终端等位置拿到了一个本身合法的请求,服务器收到第二次请求时,它仍然可能认为这是一个合法请求。OWASP 也强调,API 的状态管理如果设计不当,可能产生 replay 和 impersonation 风险。
三、哪些 API 最容易出现重放?
| 场景 | 为什么危险 | 典型问题 | | — | — | — | | 支付/转账 | 请求本身就是一次业务动作 | 重复扣款、重复转账 | | 优惠券/积分 | 一次性资源可能被重复领取 | 重复领取、积分刷取 | | 验证码/一次性链接 | 只要仍然有效就可能再次使用 | 验证码重复验证、链接重复操作 | | 订单确认/提交 | 前端按钮可能被连续点击 | 重复创建、重复提交 | | 管理操作 API | 请求携带管理员权限 | 重复执行敏感操作 |
四、最常见的错误:只做身份认证,不做”请求唯一性”
例如接口收到:
Authorization: Bearer eyJ...
POST /api/transfer
{"to":"A1001","amount":1000}
开发人员可能会认为:Token 有效,所以允许操作。但 Token 解决的是”你是谁”,并没有解决”这一次操作是不是刚刚已经执行过”。如果这个请求被复制十次,Token 仍然有效,那么服务器可能执行十次。
因此要把三个问题分开:
- 认证 解决”谁能调用”
- 授权 解决”能不能做这件事”
- 防重放 解决”同一个合法动作能不能被再次利用”
五、怎么防?最常见的三种方案
1. Nonce:给每次请求一个唯一编号
Nonce 可以简单理解成”一次性号码”。例如:
POST /api/pay
X-Nonce: 8f3c9a21
{"orderId":"10086","amount":99}
服务端收到后,把 nonce 与用户、接口或业务动作绑定并记录。第一次使用成功,第二次再收到相同 nonce,就直接拒绝。关键不是”随机字符串长得复杂”,而是服务端必须真正检查它是否已经使用过。
2. Timestamp:限制请求有效时间
例如请求中加入 timestamp=当前时间。服务器只允许请求在一个很短的时间窗口内有效,比如几十秒或几分钟。这样即使攻击者拿到请求,过了有效期也无法继续使用。
但时间戳最好不要单独使用:如果攻击者在有效窗口内快速重放,请求依然可能成功。因此实际设计中通常会结合 nonce、签名和服务端去重。
3. Idempotency Key:让同一个业务请求只产生一次结果
对于支付、订单创建等业务,可以让客户端为一次业务操作生成唯一的 Idempotency-Key。服务端第一次处理时保存”Key → 处理结果”,后续收到相同 Key 时,不再重复执行,而是返回之前的处理结果。
这个方案特别适合”网络超时导致客户端不知道请求到底成功没”的情况:客户端可以安全重试,而不会因为重试造成重复扣款或重复下单。
六、签名能不能防重放?
很多 API 会使用 sign=HMAC(...) 或其他数字签名。签名可以防止攻击者偷偷修改参数,但**”签名正确”不等于”不能重放”**。
如果攻击者拿到的是一整条合法请求:参数没改、签名也没改,那么服务器重新验证签名时仍然会通过。
因此更合理的设计是:
签名 = 用户/应用身份 + HTTP 方法 + URL + 请求参数 + timestamp + nonce
然后服务端同时检查:
- 签名是否正确
- 时间是否在窗口内
- nonce 是否已经使用
这样才能同时解决”篡改”和”重放”。
七、实际测试时怎么判断是不是重放漏洞?
安全测试人员可以先抓取一条正常请求,然后在不修改关键参数的情况下重复发送,重点观察:
| 测试点 | 判断思路 | | — | — | | 完全重复发送 | 第二次是否仍然成功? | | 延迟后发送 | 几分钟后请求是否仍有效? | | 修改 nonce | 服务端是否真正校验唯一性? | | 保留相同签名重放 | 是否只是校验签名,没有防重放? | | 并发发送相同请求 | 多个相同请求是否同时执行? | | 退出登录后重放 | 旧 Token/请求是否仍能执行敏感操作? |
八、给开发/测试的 Checklist
| 检查项 | 开发关注点 | 测试关注点 | | — | — | — | | 敏感接口是否防重放 | 支付、转账、领券等需要考虑唯一性 | 重复发送同一请求 | | 是否使用 nonce/幂等键 | 服务端保存并校验使用状态 | 重复 nonce/Key 是否被拒绝 | | 是否校验时间窗口 | 限制请求最大有效时间 | 延迟重放旧请求 | | 签名是否绑定动态字段 | 把 timestamp、nonce 纳入签名 | 尝试原签名重复发送 | | 是否考虑并发 | 避免两个相同请求同时通过 | 并发发送相同请求 |
九、最后总结
API 重放攻击并不神秘,它利用的是一个很朴素的问题:一条本来合法的请求,为什么可以被再次使用?
只做 Token 校验,不代表防重放;只做 HTTPS,也不代表防重放;只做签名,同样不一定防重放。
真正有效的思路,是让一次业务请求具备**”唯一性”和”有效期”**,常见组合就是:
nonce + timestamp + 签名 + 服务端去重/幂等
尤其是支付、转账、订单提交、优惠券、验证码、管理员操作等接口,不要只问”这个用户有没有权限”,还要问一句:“这个请求,是不是已经执行过了?” 这往往就是发现 API 重放漏洞的关键。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:小新的安全运营笔记 小新 小新《API 重放攻击:同一个请求为什么”再发一次”,业务就又执行了一遍?》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论