签名解决什么问题
消息签名的主要目的,是让接收方确认消息来自持有密钥的一方,并检查参与计算的内容是否被改变。签名不等于加密:加密关注内容是否可见,签名关注来源和完整性。
实际系统通常同时使用 HTTPS 和消息签名。HTTPS 保护传输通道;消息签名可以在消息经过代理、队列或日志系统后继续验证关键字段。
HMAC
HMAC 是基于密码散列函数和共享密钥构造的消息认证机制。发送方和接收方持有同一密钥,对相同输入计算结果。接收方使用恒定时间比较方式验证结果,避免普通字符串比较带来的额外信息泄露。
signature = HMAC-SHA256(secret, canonical_message)
摘要算法名称、输出编码方式和签名字段名都应写入接口规范。不能只写“按规则签名”,否则不同语言实现容易产生不一致。
规范化字符串
同一组数据可能有不同文本表现,例如字段顺序、空格、大小写、数字格式和字符编码。签名前需要把数据转换为唯一、稳定的规范形式。
- 确定参与签名的字段,排除签名字段本身。
- 按固定规则排序,明确字段名大小写。
- 统一 UTF-8 编码、空值规则和转义方式。
- 明确正文是签原始字节、摘要值还是解析后的字段。
method\n
path\n
timestamp\n
nonce\n
body_digest
服务端验签必须使用实际收到的数据重新构造字符串,不能直接信任客户端提交的“待签名内容”。
时效与防重复
正确的签名只能证明消息由密钥持有者生成,不能自动阻止旧消息再次出现。常见做法是加入时间戳、随机值和唯一请求编号,并设置允许的时间偏差。
服务端应记录已经接受的唯一编号或随机值。在有效窗口内再次出现时,返回之前的处理结果或拒绝重复处理。系统时钟需要保持同步,但也要预留合理误差。
密钥管理
密钥不应出现在前端源码、公开仓库、普通日志或错误响应中。测试环境与正式环境应使用不同密钥,并保留密钥版本,以支持平滑轮换。
轮换期间可以短期同时接受新旧两个版本,但新请求只使用新版本签名。发现异常时,应能停用单个密钥,而不影响其他身份。
签名校验失败时,外部响应只需返回稳定错误类型;内部日志再记录密钥版本、请求编号和失败阶段,不记录完整密钥。