← 返回题目列表

什么是重放攻击?接口如何用时间戳、Nonce 和签名防重放?

高频 中等 第 12 / 27 题 更新于 2026/07/31
重放攻击Nonce签名时间戳

简化版

重放攻击是攻击者截获一次合法请求后,不修改内容直接再次发送,让服务端重复执行操作。防御通常使用 HTTPS、时间戳、Nonce、请求签名和幂等控制:服务端校验请求是否在有效时间窗内、Nonce 是否用过、签名是否匹配。

详细版

重放攻击的关键不是伪造内容,而是复用旧的合法内容。比如抓到一次扣款请求,如果服务端只校验签名合法,却不校验时间和唯一性,攻击者可能重复发送导致多次扣款。

常见方案是把方法、路径、参数摘要、时间戳、Nonce 一起参与签名。服务端先校验时间窗口,例如 5 分钟内有效,再检查 Nonce 是否已使用,最后验证签名。关键业务还要有幂等号,避免网络重试和恶意重放造成重复执行。

完整版教学

一、重放攻击的本质

重放攻击利用的是“旧请求曾经合法”。攻击者不一定知道密钥,也不一定能改参数,只要能拿到一份完整请求并再次发送,就可能让服务端重复执行。

合法请求: pay order=100 amount=99 sign=abc
攻击者复制
再次发送: pay order=100 amount=99 sign=abc

如果服务端只看签名正确,就会误以为这是一次新的合法请求。

记忆钩子:重放攻击不是“改请求”,而是“旧请求再次被当成新请求”。

二、为什么 HTTPS 还不够

HTTPS 能防止大多数网络窃听和篡改,但不能覆盖所有重放来源。比如客户端日志泄露、代理层记录、内部服务调用被复制、恶意客户端自己重复发送。

TLS 防链路窃听
时间戳/Nonce 防旧请求重复使用
幂等号防业务重复执行

所以防重放通常是应用层协议设计的一部分,尤其是开放 API、支付、下单、回调接口。

三、时间戳窗口怎么用

请求里带时间戳,服务端只接受当前时间附近的请求。例如允许误差 300 秒,超过就拒绝。

server_now = 12:00:00
allowed window = 11:55:00 ~ 12:05:00
request_ts = 11:40:00 -> reject

时间窗口能缩短旧请求可利用时间,但不能阻止窗口内重复发送,所以还需要 Nonce。

四、Nonce 为什么必须记录

Nonce 是一次性随机数。服务端要记录某个客户端在时间窗口内用过的 Nonce,再次出现就拒绝。

key = client_id + nonce
Redis SETNX key 1 EX 300
成功: 第一次使用
失败: 重放请求

如果只要求客户端带 Nonce 但服务端不记录,它就没有防重放作用。记录时间通常与时间戳窗口一致。

五、签名应该覆盖哪些内容

签名要覆盖请求方法、路径、查询参数、body 摘要、时间戳、Nonce 和客户端标识。否则攻击者可能复用签名到另一个路径或替换未签名字段。

string_to_sign =
METHOD + "\n" +
PATH + "\n" +
SHA256(body) + "\n" +
timestamp + "\n" +
nonce

签名算法常用 HMAC-SHA256。服务端使用共享密钥重新计算并做恒定时间比较,避免时序侧信道。

六、幂等和防重放的区别

防重放关注“同一请求不能被旧包重复利用”,幂等关注“业务重复调用不会重复产生副作用”。两者经常一起用,但不是同一件事。

机制解决问题示例
时间戳旧请求过期5 分钟窗口
Nonce同窗口重复请求SETNX 去重
签名请求未被篡改HMAC
幂等号业务重复执行order_id/request_id

支付、创建订单、发券这类接口,只有防重放没有幂等仍然不够稳。

七、开放 API 的落地流程

开放 API 通常给每个调用方分配 app_idsecret。客户端按约定构造待签名字符串,服务端根据 app_id 找到密钥重新计算签名。签名失败、时间过期、Nonce 重复都要拒绝。

client sends: app_id, timestamp, nonce, signature
server loads secret by app_id
server verifies time -> nonce -> signature

校验顺序也有讲究:先做便宜的时间窗口和格式校验,再做存储查询和签名计算,避免攻击者用垃圾请求耗尽资源。

八、回调接口的特殊点

支付回调、消息回调、物流回调经常会被服务方重试。你的服务不能把所有重复回调都当攻击,也不能重复执行业务动作。正确做法是验证来源签名,再用业务单号做幂等。

same callback + same order_id
first time: update paid
second time: return success without duplicate update

这类场景要把“合法重试”和“恶意重放”同时考虑,日志里也要能区分。

九、常见误区与追问

  • 误区:签名正确就一定不是重放。 旧请求签名也正确,必须校验时间戳和 Nonce。
  • 误区:Nonce 不用存储。 不记录已用 Nonce,就无法判断重复。
  • 误区:HTTPS 后不需要应用层防重放。 开放 API、回调和内部复制请求仍可能需要。
  • 追问:时间窗口设多大? 要平衡时钟误差和攻击窗口,常见是 1 到 5 分钟。
  • 追问:服务端时间不一致怎么办? 使用 NTP,对客户端误差给小窗口,并监控异常。
  • 追问:签名为什么要包含 path 和 body? 防止签名被挪用到其他接口或参数被替换。
  • 追问:Redis 记录 Nonce 挂了怎么办? 要按业务决定 fail-open 或 fail-close,支付类通常更保守。

十、加强记忆

重放攻击要按“旧请求再次有效”来理解。防线是四件套:HTTPS 防链路窃听,时间戳限制旧请求窗口,Nonce 证明一次性,签名绑定请求内容,幂等号兜住业务重复执行。面试回答时把这几层分清,就能从协议安全讲到工程落地。