接口签名与防重放怎么设计?一次讲清时间戳、nonce、签名串与安全校验链路
大家好,我是一名有 4 年工作经验的 Java 后端开发。
很多对外接口、开放平台接口,真正的难点不只是 token 校验,还包括请求有没有被篡改、有没有被重放。
这篇文章我想系统聊一聊接口签名与防重放到底怎么设计。
🦅个人主页
🐼
文章目录
- 接口签名与防重放怎么设计?一次讲清时间戳、nonce、签名串与安全校验链路
-
- [一、为什么 token 不够](#一、为什么 token 不够)
- 二、典型签名字段有哪些
- 三、防重放怎么做
-
- [3.1 时间戳校验](#3.1 时间戳校验)
- [3.2 nonce 去重](#3.2 nonce 去重)
- [3.3 签名串校验](#3.3 签名串校验)
- 四、推荐校验顺序
- 五、最容易踩的坑
-
- [5.1 nonce 不落库 / 不落缓存](#5.1 nonce 不落库 / 不落缓存)
- [5.2 签名串规则不统一](#5.2 签名串规则不统一)
- [5.3 请求体太大直接参与签名](#5.3 请求体太大直接参与签名)
- [5.4 只验签,不验时间戳](#5.4 只验签,不验时间戳)
- 六、面试中怎么回答
- 七、总结
- 八、结尾
一、为什么 token 不够
很多人会觉得:
- 有 token 就够安全了
但 token 解决的更多是:
- 你是谁
它不完全解决:
- 请求体有没有被篡改
- 这个请求是不是旧请求重放
所以开放接口和高价值接口通常还会做:
- 签名
- 时间戳校验
- nonce 防重放
二、典型签名字段有哪些
常见会带这些:
appKeytimestampnoncesign
有时还会加:
- 请求路径
- 请求方法
- 请求体摘要
签名的核心目标是:
- 保证请求没被改
- 保证请求不是旧包重放
三、防重放怎么做
3.1 时间戳校验
例如只允许:
- 前后 5 分钟内的请求
3.2 nonce 去重
同一个 appKey + nonce 在有效窗口内只能用一次。
通常可以放 Redis:
text
sign:nonce:{appKey}:{nonce}
3.3 签名串校验
后端按同样规则重新计算签名,和传入的 sign 比较。
四、推荐校验顺序
我更建议按这个顺序做:
- 校验 appKey 是否合法
- 校验 timestamp 是否过期
- 校验 nonce 是否重复
- 重新生成签名并比对
- 通过后再进入业务逻辑
这个顺序比较稳,也更容易排查。
五、最容易踩的坑
5.1 nonce 不落库 / 不落缓存
那就无法真正防重放。
5.2 签名串规则不统一
前后端一旦理解不同,很容易验签失败。
5.3 请求体太大直接参与签名
要考虑稳定的摘要方式,而不是直接拼接大文本。
5.4 只验签,不验时间戳
那旧请求依然可能被重放。
六、面试中怎么回答
如果面试官问你:
接口签名和防重放一般怎么做?
你可以这样回答:
第一,token 更多解决身份识别问题,而签名和防重放主要解决请求是否被篡改、是否被恶意重复发送的问题,所以对开放平台接口或高价值接口,我通常会补充时间戳、nonce 和签名机制。
第二,常见做法是请求里带 appKey、timestamp、nonce 和 sign,后端先校验时间戳是否在有效窗口内,再用 Redis 等方式确保同一个 nonce 只使用一次,最后重新计算签名并比对。
第三,真正落地时我会特别注意签名串规则统一、请求体摘要稳定和错误码可排查性,否则验签问题会很难定位。
七、总结
接口签名真正难的不是"加个 sign 字段",而是如何把:
- 身份识别
- 参数防篡改
- 请求防重放
真正串成一套稳定的校验链路。
如果只记一句结论,我觉得可以记住这句:
对外高价值接口最稳的安全思路通常不是只靠 token,而是"token + timestamp + nonce + sign"组合校验。
八、结尾
如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、关注。
后面我会继续整理一些更偏实战的 Java 后端和开放平台设计文章,尽量少写空泛概念,多写真实项目里会踩到的坑。