抓到一个下单请求后原样重发 10 次,10 次都创建了订单,签名每次都校验通过,请求体里的 timestamp 和 nonce 服务端都收到了但没参与验签。碰到这种情况,我一般先确认改动有没有真的生效。
原因不复杂,签名串只拼了业务字段,timestamp 和 nonce 在签名之外。服务端也没有校验时间窗口和 nonce 是否用过。攻击者拿到一次请求就能无限重放。
「请求重放」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。改完顺手把文档补一句,省得下次自己重新推一遍。
redis-cli SET nonce:8f3a1c 1 EX 300 NX curl -s -X POST http://127.0.0.1:8080/api/orders -H 'X-Nonce: 8f3a1c' -d @replay.json
监控和日志的时间要对上,时区不一致会多绕很大一圈。临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。
具体做法是,把 timestamp 和 nonce 按固定顺序拼进签名串;服务端校验时间戳与当前时间相差不超过 5 分钟;nonce 写进 Redis 并设置与时间窗相同的过期时间 重复直接拒绝;用同一个请求连发 10 次确认只有第一次成功。
最后用这个标准收尾,第二次重放返回 409 nonce 已使用 Redis 里只留下一条记录。
