redis-cli SETNX nonce:9f2c 1 EX 600
python replay.py --file event.json --times 20

抓包把一条回调原样重放 20 次,20 次都返回 success,账户余额被加了 20 次。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。

原因不复杂,接口只校验签名和时间戳,nonce 收下就丢,没有存也没有查。窗口期内原样重放,所有校验都能通过,业务侧也没有第二道判重。

「回调重放拦截」排查到最后往往是很小的一处差异,前面那些复杂猜测可以先放一放。改动写完就同步给同事,下一个人踩同一个坑,成本还是你的。

验证用真实数据走一遍,测试数据太干净,边界情况根本碰不到。能分两步做的操作就别合成一步,中间看一眼返回值,出问题好判断。

报错里带路径的,先去看那个路径在不在、权限对不对。

处理上按这个顺序:用 Redis 的 SETNX 存 nonce 过期时间设成窗口的两倍;同一个 nonce 第二次进来直接返回已处理;业务侧再按事件 id 建唯一索引兜底;写重放脚本验证拦截生效。

改完只确认一件事:重放脚本从第 2 次起返回 duplicated 余额只增加一次。

作者 9823189