dev

Hash vs HMAC:校验和 API 签名怎么选

判断 checksum、文件指纹、API 签名和 webhook 校验中什么时候用普通 Hash,什么时候必须用 HMAC,并系统检查算法选择、输入字节、输出编码、共享密钥、JWT 解码边界和生产 secret 处理风险,避免把摘要误当身份验证或把 HMAC 误当加密方案来使用。

Hash 和 HMAC 都可能输出一长串十六进制字符串,但它们回答的问题完全不同。Hash 回答“这个输入是否生成了这个摘要”;HMAC 回答“是否有持有共享密钥的人,针对这段消息生成了这个摘要”。如果选错,checksum 很容易被误当成身份验证。

普通 Hash 适合非敏感完整性检查

当目标是可重复比较时,可以使用 Hash Generator。同一输入和同一算法会得到同一摘要,因此 hash 适合文件 checksum、缓存 key、去重、内容指纹,以及确认复制文本是否变化。

但 hash 不能证明输入是谁创建的。任何拿到相同文本的人,都能计算出相同 hash。如果一个公开 webhook body 只是用 SHA-256 做摘要,但没有 secret 参与,攻击者修改 body 后也能重新计算匹配摘要。这个摘要可以发现意外损坏,但不能认证发送者。

算法选择也很重要。MD5 和 SHA-1 仍可能出现在旧文件校验流程里,但不应作为新的安全边界。如果是你能控制的新完整性检查,SHA-256 通常更适合作为默认选择。如果你要对照供应商提供的 checksum,就使用供应商发布的算法,并按它提供的编码形式精确比较。

需要共享密钥验证时使用 HMAC

当验证过程需要 secret key 参与时,应使用 HMAC Generator。HMAC 会把消息、hash 函数和 secret key 组合成 keyed message authentication code。接收方使用相同消息和相同 secret 重新计算;如果结果匹配,就能说明发送方知道这个 secret,并且消息签名后没有被篡改。

这就是 HMAC 常用于 webhook 签名和 API 请求签名的原因。支付平台、部署平台或内部服务可以对请求 body 签名;你的服务端用共享 secret 重新计算签名,再决定是否信任这个事件。

HMAC 不是 encryption。消息内容仍然可见,除非另有传输层保护或加密层。HMAC 验证真实性和完整性,但不会隐藏内容。

调试签名时检查真实字节,而不是肉眼文本

签名不匹配经常不是算法错,而是输入不同。发送方可能签的是原始请求 body,而你的代码签的是解析后再序列化的 JSON 对象。这两段字节不保证相同。空格、字段顺序、换行风格、字符编码和转义方式都可能改变字节序列。

调试 API 签名时,应捕获接收到的原始 body。确认算法,例如 HMAC-SHA256。确认 key 格式:普通文本、hex、Base64,还是平台 secret 字符串。确认输出编码:hex digest、Base64,还是带 `sha256=` 这类前缀的 header 值。两边必须比较同一种表示。

如果供应商签的是时间戳加 body,就必须按文档把时间戳精确拼进去。如果签名 header 包含多个版本或多个签名,就比较文档指定的那一个。很小的格式差异也足以让 HMAC 完全不同。

不要把 Hash 或签名当成可解码内容

Hash 在实际使用中是单向的。工具可以拿已知输入和已知 hash 做比较,但不能把安全摘要“解码”回原始消息。除非输入空间极小或早已知道,否则不要把现代 hash 当成可逆编码。

HMAC 输出也不是用来解码的。正确验证方式是用同一消息和同一 secret 重新计算,再做安全比较。如果结果不同,常见原因是 secret 错、输入字节错、算法错、编码错或消息被改过。

JWT 解码只是查看,不是验证

JWT 场景也很容易混淆。可以用 JWT Decoder 查看 header 和 payload,但解码只是读取 Base64URL 编码的 JSON,不代表 token 有效。真正的签名验证需要正确算法、key、issuer、audience、过期时间等规则,并且应在负责信任决策的系统中完成。

如果你只是想理解 token 里有哪些 claims,解码足够。如果你要接受登录、授权 API 调用,或信任类似 webhook 的 token,只解码远远不够。

浏览器检查时不要暴露真实 Secret

浏览器工具适合学习、比较示例值和调试非生产样例。不要把生产 API secret、webhook signing key、密码重置 token 或客户凭据粘贴进浏览器工具。使用 `test_secret_123` 这类模拟 secret,保留相同编码形态,用安全数据复现问题。

写内部排查记录时,建议记录算法、被签名输入的构造方式、key 来源、输出编码和比较规则。这样以后排查签名失败会快很多,也能减少把 hash 当 HMAC、把 HMAC 当加密的误用。

选择检查清单

  • 只需要比较两个非敏感值是否一致:用 hash。
  • 需要证明发送方知道共享 secret:用 HMAC。
  • 需要隐藏内容:使用加密和传输层保护,HMAC 不隐藏内容。
  • 只想查看 JWT claims:解码 token。
  • 需要信任 JWT:在后端验证签名和 claims。
  • HMAC 不匹配:检查原始字节、算法、key 格式、输出编码和 header 格式。

FAQ

HMAC 和 encryption 一样吗?

不一样。HMAC 使用共享密钥认证消息,但不会隐藏消息内容。

API 签名可以用 MD5 吗?

新安全敏感设计应避免使用 MD5。如果现有 API 强制要求旧算法,只把它作为兼容要求处理,不要把它当作新系统模板。

为什么我的 HMAC 和平台 header 对不上?

最常见原因是签了重新序列化后的 JSON,而不是原始 body;或者 secret 格式、算法、输出编码、header 前缀不一致。

Hash 能证明消息是谁发的吗?

不能。普通 hash 没有 secret。任何知道输入和算法的人,都可以计算同一个摘要。

继续阅读