API重放攻击:同一个请求为什么”再发一次”,业务就又执行了一遍?

admin 2026-09-15 04:44:20 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文系统讲解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 重放攻击:同一个请求为什么”再发一次”,业务就又执行了一遍?》

评论:0   参与:  0