CodeKitHub
编码工具

HMAC 生成器

最后更新:

这个工具以 SHA-1、SHA-256、SHA-384 或 SHA-512 作为底层哈希函数,从一个密钥和一段消息计算出 HMAC(基于哈希的消息认证码)。与普通哈希不同,HMAC 需要一个共享密钥参与运算,因此它不仅能证明消息在传输中未被篡改,还能证明消息确实来自持有该密钥的一方——这正是 API 用 HMAC 给请求签名、webhook 用它来验证发送方身份的原因。所有计算都通过浏览器内置的 Web Crypto API 在本地完成,你的密钥和消息永远不会发送到任何服务器。

HMAC-SHA1
HMAC-SHA256
HMAC-SHA384
HMAC-SHA512

工具介绍

HMAC 全称 Hash-based Message Authentication Code(基于哈希的消息认证码)。它把一个密钥、一段消息和一个标准哈希函数(如 SHA-256)结合起来,生成一个固定长度的摘要。持有相同密钥并输入相同消息的任何人,都会算出完全相同的 HMAC——但如果不知道密钥,即使清楚使用的是哪种哈希算法,也几乎不可能为某条消息伪造出一个有效的 HMAC。

这正是它与普通哈希的关键区别:普通哈希(MD5、SHA-256 等)只以消息本身为输入,任何人都能算出来,因此它证明不了任何关于"谁生成了它"的信息。HMAC 的输入是消息*加上*一个密钥,所以一个有效的 HMAC 能证明发送方确实持有那个密钥——它是一种身份认证机制,而不只是完整性校验。

HMAC 由 NIST 在 FIPS 198-1 中正式标准化,并在 IETF RFC 2104 中定义为互联网协议规范。这个工具使用浏览器原生的 Web Crypto API(`crypto.subtle.sign` 配合 HMAC 算法)来计算 HMAC,它严格遵循 RFC 2104 的实现,而不是手写的 JavaScript 版本。

为什么使用它?

  • 正在排查一个 webhook 处理逻辑,所有请求都被判定为“签名无效”——把共享密钥和完全原始的请求体粘贴到这里自己算一遍 HMAC,看看问题到底出在服务端的比对逻辑上,还是别的地方。
  • 第一次实现 API 请求签名功能,想在把代码接到线上接口(签名错了会被静默拒绝)之前,先确认自己算出来的 HMAC-SHA256 是不是对的。
  • 需要给某个用共享密钥认证的服务生成一次性的签名 URL 或令牌,比起专门写个脚本,直接在这里算一次 HMAC 更快。
  • 在教别人或自己在学 HMAC 和普通哈希的区别,想亲眼看到同一条消息只要换一个密钥,摘要就完全变了样。
  • 想拿同一个密钥和消息,对比一下 HMAC-SHA1 和 HMAC-SHA256 的输出,好在把某个遗留系统的签名方案迁移到更强算法之前先确认清楚。
  • 100% 本地运行:你的密钥和消息不会离开浏览器,用真实密钥测试也很安全。

使用方法

  1. 在"密钥"字段中输入你的密钥。
  2. 在"消息"字段中输入需要认证的消息内容。
  3. HMAC-SHA1、HMAC-SHA256、HMAC-SHA384、HMAC-SHA512 的结果会即时生成(如果目标系统要求大写,勾选"大写输出")。
  4. 点击你需要的那个 HMAC 值旁边的"复制"。

示例

输入

Secret Key: key
Message: The quick brown fox jumps over the lazy dog

输出

HMAC-SHA256: f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
HMAC-SHA1: de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9

这是一个公开发布的标准测试向量:使用密钥 "key" 和这段完全相同的消息,任何正确的实现都会得到相同的 HMAC-SHA256 和 HMAC-SHA1 结果,你可以用它来独立验证这个工具的输出是否正确。

HMAC 与普通哈希:什么时候需要密钥

决定性的问题是:你需要证明这份摘要是谁生成的,还是只需证明内容没被改动?如果公开的校验和就足够了——比如验证下载文件是否与发布方公布的一致、给记录去重——普通哈希就能胜任,任何人都能验证,不需要密钥。但如果你需要证明这份摘要只可能是持有特定密钥的一方生成的——比如验证 API 调用方身份、信任某个 webhook 的发送方——就必须用 HMAC,因为普通哈希会让一个完全不掌握密钥的攻击者,拥有和真实发送方同样的能力去伪造出一份有效摘要。

多算法哈希生成器 · JWT 解码器 · MD5 生成器

四种 HMAC 算法对比

四种算法都基于 RFC 2104 中同样的 HMAC 构造,区别仅在于底层哈希函数不同,因此输出长度也不同。

算法输出长度典型用途
HMAC-SHA1160 位(40 个十六进制字符)遗留 API、较旧的 OAuth 1.0a 签名
HMAC-SHA256256 位(64 个十六进制字符)API 请求签名、JWT HS256、webhook 验证
HMAC-SHA384384 位(96 个十六进制字符)需要更长输出的高安全等级签名场景
HMAC-SHA512512 位(128 个十六进制字符)高安全性应用中要求最长摘要的场景

常见使用场景

  • 用共享密钥对发出的 API 请求签名,让服务器能验证调用方身份。
  • 验证收到的 webhook 负载(Stripe-Signature、GitHub 的 X-Hub-Signature-256 等请求头都使用 HMAC-SHA256)。
  • 生成并校验用 HS256/HS384/HS512 签名的 JWT 中的签名部分。
  • 在部署前,测试自己的服务端或客户端 HMAC 实现是否与预期输出一致。

一步步排查 webhook 签名不匹配的问题

签名校验失败是最常见的 HMAC 相关 bug 之一,而且几乎总能追溯到:你实际哈希的字节内容,和发送方真正哈希的字节内容不一致——而不是算法本身出了问题。

首先确认你哈希的是收到时的原始请求体,而不是经过框架解析成对象之后的版本——很多 Web 框架会在你接触 `req.body` 之后,以某种方式重新缓冲和编码请求体,悄悄改变了空白字符或键的顺序。接下来检查密钥:不少服务商会为每个 webhook 端点或环境发放不同的签名密钥,从错误的后台页面复制来的密钥会造成一种看起来和代码 bug 一模一样的不匹配。最后检查输出的编码格式:有的服务要求 HMAC 以小写十六进制表示,有的要求 base64,即使底层计算完全正确,用错编码格式去比对同样会失败。用完全相同的原始文本和密钥在这里复现一遍,就能确定问题出在比对逻辑本身,还是出在喂给它的输入上。

常见问题

什么是 HMAC?

HMAC(基于哈希的消息认证码)把一个密钥和一段消息结合,通过哈希函数生成一个摘要,既能证明消息的完整性,也能证明发送方持有该密钥。它定义于 NIST FIPS 198-1 和 IETF RFC 2104。

HMAC 和普通哈希有什么区别?

普通哈希(SHA-256、MD5 等)只以消息为输入——任何人都能计算,所以它只能证明消息没被篡改,无法证明是谁发送的。HMAC 的输入是消息加密钥:如果你需要证明某条消息来自持有特定密钥的一方(比如 API 签名、webhook 发送方),就需要 HMAC。如果只是想校验文件或消息是否被更改过,不关心作者身份,普通哈希就够了。

我的密钥会被发送到服务器吗?

不会。这个工具完全在浏览器内使用 Web Crypto API 计算 HMAC。你的密钥和消息不会被传输到任何地方——你可以放心地用真实的生产环境密钥进行测试。

该用 SHA-1、SHA-256、SHA-384 还是 SHA-512?

没有特殊要求的话,优先用 HMAC-SHA256——它是 API 签名事实上的行业标准(AWS、Stripe、GitHub webhook 及大多数现代 API 都在用),安全边际也很充足。HMAC-SHA1 在一些遗留系统中仍很常见(比如较旧的 OAuth 1.0a 实现),但其底层的 SHA-1 哈希被认为强度较弱;HMAC-SHA384/512 则用于明确需要更长输出或更高安全边际的场景。

既然普通 SHA-1 已被攻破,HMAC-SHA1 还安全吗?

2017 年针对 SHA-1 的碰撞攻击破解的是 SHA-1 作为普通哈希函数的安全性,但 HMAC-SHA1 仍被认为在密码学上是可靠的,因为 HMAC 的安全性并不像普通哈希那样依赖碰撞抗性。尽管如此,新系统还是建议优先使用 HMAC-SHA256 或更高强度算法——这样做没有任何实际代价,还能彻底避开这个争议。

HMAC 在实际中有哪些常见用途?

为 REST API 请求签名,让服务器能验证调用方确实持有共享的 API 密钥;验证来自 Stripe、GitHub、Shopify 等服务的 webhook 负载,确认请求确实来自它们本身而非伪造;为双因素认证生成基于时间的一次性密码(TOTP/HOTP);以及用 HS256/HS384/HS512 算法对 JWT 令牌签名。

为什么用同一个密钥,我的 webhook 签名和这个工具算出来的 HMAC 对不上?

最常见的原因是:传给 HMAC 函数的原始请求体,和发送方实际参与哈希计算的字节并不完全一致——一个重新序列化过的 JSON 请求体(键的顺序、空白字符或转义方式和原始字节不同)即使“看起来一样”,算出来的 HMAC 也会完全不同。一定要用未经任何 JSON 解析的、完全原始的请求体/文本去计算 HMAC,并再三确认用的密钥是否正确(有些服务会为每个 webhook 端点单独发放不同的签名密钥)。

密钥的长度会影响 HMAC 的安全性吗?

在一定范围内会——一个非常短或容易猜到的密钥(比如“password”或 4 位数字 PIN)无论哈希算法多强,都是整个系统里最薄弱的一环,因为攻击者可以直接暴力破解短密钥。HMAC 的设计建议密钥长度至少要达到底层哈希输出长度;超过这个长度之后,再增加密钥长度对安全性的提升就不明显了。

同一个密钥下,两条不同的消息会算出相同的 HMAC 吗?

理论上有可能,因为 HMAC 是把无限的输入空间映射到固定长度的输出——但对于 SHA-256 及以上强度,用已知的任何攻击手段刻意找出这种碰撞,在计算上被认为是不可行的,这也正是 HMAC-SHA256 尽管在数学上存在这种可能性、依然被广泛信任用于生产环境签名的原因。

这个工具计算 HMAC 的方式,和我后端语言(Node、Python 等)算出来的是一致的吗?

是一致的——因为这个工具使用的是浏览器原生的 Web Crypto API,而不是手写实现,它遵循的是和 Node 的 crypto 模块、Python 的 hmac 库以及几乎所有正确实现一样的 RFC 2104 规范。如果在这里算出的结果和你后端一致,就是确认你后端代码正确实现了规范的可靠方式。

相关工具