SheepDev

哈希、ID与随机数

Webhook 签名不一致,如何检查 HMAC 条件?

使用工具

Webhook 的 JSON 看起来正确,签名检查却失败。语义相同还不够,因为 HMAC 计算的是密钥与消息字节的组合。整理键顺序或空白后的文本,可能已不是发送方签名的原文。这里用可公开的练习密钥逐项定位。

用已知密钥和正文确认计算路径

选择 SHA-256、十六进制,密钥输入 key,正文输入 The quick brown fox jumps over the lazy dog,不加额外空白。结果应如下。这是公开练习数据,不能当生产密钥;先通过已知小例子,比只试真实请求更容易定位。

练习 HMAC-SHA-256
f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8

这不是正文的普通 SHA-256,也不是简单拼接密钥与正文再哈希。协议规定 HMAC-SHA-256 就要使用该构造;SHA-384、SHA-512 也应查提供方规范,不凭签名外观猜测。

仅格式化 JSON 也会改变签名

下面 JSON 含义相同,但空格、换行或键顺序会改变 HMAC 的字节输入。验证前先 parse 再 stringify 或格式化,可能无法重现发送方正文。协议签原始正文时,就必须保留原字节验证。

含义相同但字节不同
{"amount":100,"currency":"JPY"}

{ "amount": 100, "currency": "JPY" }

LF 和 CRLF 也不同。追查 HTTP 库、保存、编辑器或复制在哪一步改变内容时,可查看字节数和十六进制。二进制正文不能随意转文本;本工具区分文件原字节与 UTF-8 文本输入。

看似相同的密钥可能代表不同字节

密钥写成 6b6579 时,要确认是六个文本字符,还是十六进制表示的三个字节。后者解码是 key,但本工具不会自动按十六进制解码密钥栏,而是使用 UTF-8 文本。Base64 密钥也一样,字面相同不一定表示正确的密钥字节。

不要把任意二进制密钥转成乱码来强行输入,应使用能接受准确字节的本地实现或提供方 SDK。检查签发、保存形式和读取时解码,比不断换密钥更有效。页面的密钥字节数也能帮助发现多余换行或漏解码。

签名对象未必只有正文

有些协议按固定顺序组合时间、HTTP 方法、路径和正文,仅输入正文不会一致。需要核对分隔符、换行、URL 编码及时间表示。本工具是通用 HMAC 计算,不会自动识别任意 Webhook 并构建签名字符串。

十六进制、Base64、Base64url 外观不同。本页面输出前两种,比较 Base64url 时须考虑表示差异。头部可能带 sha256= 前缀,但它未必属于摘要;应按协议选择比较部分,不能随意删字符凑一致。

HMAC 一致只是接收验证的一部分

结果一致不能证明请求新鲜或未被重放。时间与 ID 的重放防护、比较实现、密钥管理属于接收端责任,本计算页面不等于完整认证。排查时逐项固定算法、密钥表示、签名字节、输出格式,才能追踪变化影响。

共享复现应使用练习密钥与虚构正文,不把生产秘密贴进聊天或工单。浏览器本地处理不消除屏幕共享和剪贴板风险;泄露后关闭页面并不能解决,应遵循提供方或组织的密钥更新流程。先用本例的公开 key 练习。

检查是否用重组 JSON 替换了签名原文

解析 JSON 后重新序列化再算 HMAC,可能改变键顺序、空白、换行和转义写法。结构相同与签名字节相同是两种检查。协议签原始正文时应保留原文;为便于比较而格式化,可能改了比较对象。

先用公开已知键和短已知正文,一次改一个条件。不一致就查算法、输出格式和键解释;已知例通过而真实数据失败,再查原字节和组装。避免记录秘密键,先用编码、长度等非秘密信息。此栏把键当 UTF-8 文本,不自动解码十六进制。

MAC 一致不验证重放防护。协议的时间戳、nonce 或事件 ID 可能还需接收方验证和去重。HMAC 是共享键认证计算,不是正文加密,应把签名排查与安全单次处理设计分开。

参考资料

使用工具

指南 →