签名验签的五个坑:顺序、编码、时钟与重放
对接第三方接口时,最常见的联调问题是「签名不一致」。九成原因是参数顺序、编码或空值处理不同。
签名机制的安全强度,取决于「规范是否唯一」与「是否防重放」。
先说结论
参数按字典序、统一编码、带时间戳与 nonce、服务端校验窗口。
- 签名串拼接规则要写进文档且唯一
- 空值与数组的处理必须明确
- 时间戳窗口 5 分钟,超出拒绝
- nonce 用 Redis 做一次性校验
漏洞是怎么产生的
签名的作用是「证明请求来自持有密钥的一方,且内容未被篡改」。它不负责保密(那是加密的事)。
重放攻击是签名机制最容易漏的一环:签名正确但请求可以被重复发送。
修复与验证
修复不是改一行代码,而是四件事一起做:
- 定义签名串规则:排序、拼接、编码、是否包含空值
- 使用 HMAC-SHA256 或 RSA/ECDSA 签名
- 请求带 timestamp 与 nonce
- 服务端校验时间窗口与 nonce 唯一性
- 密钥按环境隔离,支持轮换
攻击面与检测点
按影响面排序,先修影响最大的:
| 坑 | 表现 | 修法 |
|---|---|---|
| 参数顺序 | 签名偶发不一致 | 统一字典序 |
| 编码 | 中文/空格出错 | 统一 UTF-8 且 URL 编码规则一致 |
| 空值 | 一方带一方不带 | 文档明确 |
| 重放 | 同请求可重复 | timestamp + nonce |

几个容易踩的坑
下面这些是最常见的错误做法:
- 用 JSON 原文签名:键顺序不同即失败
- 忽略换行与空格:肉眼看不出差异
- 不校验时间戳:签名永久有效
- 密钥硬编码在客户端:等于公开
写在最后
签名实现的验收标准:换一种语言实现,能算出同样的结果。
安全不是一次加固,是持续的假设:假设输入不可信、假设边界会破、假设有人会看错。
评论 (3)
修复清单比漏洞描述有用多了,很多文章只讲怎么打不讲怎么防。
白名单那条永远是最有效的,正则黑名单迟早绕过。
建议再补一条:把这类检查加到 CI 里,靠人记必然漏。
发表评论