上传文件
  1. base64hub
  2. 密钥与哈希
  3. HMAC 生成器

HMAC 生成器(Base64)

输入消息和密钥,即可得到 Base64、Base64URL 和 hex 形式的 HMAC 签名。用它调试 Webhook 签名和 API 请求签名,不必把密钥发送到任何地方。

免费 无需注册,不限次数 本地 不上传任何内容 密钥格式 文本、hex 或 Base64 字节 更新于 2026年10月27日

在你的浏览器中处理。此页面无法将你的数据发送到任何地方: 我们如何确认

如何计算 Base64 格式的 HMAC

  1. 已选中 HMAC 模式和 SHA-256。如果你的 API 使用 SHA-1、SHA-384、SHA-512 或 MD5,请在 算法 中另选。
  2. 输入 密钥,并设置 密钥格式:普通的密钥字符串选文本(UTF-8),密钥以编码字节形式给出时选 Hex 或 Base64。
  3. 在 文本 中输入或粘贴消息,或把 输入 切换为 文件,拖入确切的载荷文件。
  4. 以 Base64、Base64URL 或 hex 复制签名。所有算法 会同时显示每种哈希的 HMAC,文档没说清用的是哪种时很有帮助。

空密钥也能接受并得出结果,同时会提示这样的 HMAC 起不到任何保护作用。

示例值

密钥为 key,消息为 The quick brown fox jumps over the lazy dog 时:

算法Base64 格式的 HMAC
HMAC-MD5gAcHE0Y+d0m5DC3CSRHidQ==
HMAC-SHA13nybhbi3iqa8ino29wqQcBydtNk=
HMAC-SHA25697yD9DBThCSxMpjmqm+xQ+9NWaFJRhdZl0edvC0aPNg=
HMAC-SHA512tCrwkFe6weLUFwjkipAuCbX/fxKrQopP6GZTxz3SSPuC+UilSfe3kaW0GRXuTR7Dk1NX5OIxclDQNyr6Lr7rOg==

HMAC-SHA256 的 hex 值是 f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8,也就是维基百科 HMAC 词条中那个熟悉的测试向量。密钥的编码方式会改变结果:把文本 a2V5 用作密钥得到 5O+7AtpguFrgIRw1qXGU+m0OaTs1oV1kwRQ/hI1WAUE=,而把 a2V5 按 Base64 读取,得到的是 key 的字节,结果又是 97yD9DBT…。

Webhook 签名:Base64 还是 hex

各服务方都用 HMAC,但输出编码和签名内容并不统一。几个文档齐全的例子:

服务方请求头算法编码签名内容
ShopifyX-Shopify-Hmac-Sha256HMAC-SHA256Base64原始请求体
Standard Webhooks(Svix)webhook-signature: v1,…HMAC-SHA256Base64id.timestamp.body,密钥取自 whsec_ 后的 Base64
TwilioX-Twilio-SignatureHMAC-SHA1Base64URL 加上排序后的 POST 参数
GitHubX-Hub-Signature-256: sha256=…HMAC-SHA256hex原始请求体
StripeStripe-Signature: t=…,v1=…HMAC-SHA256hextimestamp.body

如果本工具算出的值与 hex 一致,而你的代码比较的是 Base64(或者反过来),说明计算没错,只是编码不同。签名内容请查阅服务方的文档;时间戳前缀是为了防止旧请求被重放。

在代码中验证签名

用恒定时间比较原始字节,并确保对收到的请求体原样计算哈希:

const crypto = require("crypto");

function verifyWebhook(rawBody, secret, signatureHeader) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest();
  const given = Buffer.from(signatureHeader, "base64");
  return given.length === expected.length && crypto.timingSafeEqual(given, expected);
}

把狐狸那句话的 Buffer 作为 rawBody,密钥为 key,再传入表中的 Base64 值,它返回 true。如果传入的是 JSON.stringify(JSON.parse(body)) 而不是原始请求体,只要服务方的 JSON 里有一个你的序列化器会丢掉的空格,它就返回 false。在 Express 中,这意味着要在 Webhook 路由上用 express.raw() 读取请求体。

Python 中的对应写法是用 hmac.new(key, body, hashlib.sha256).digest(),对结果做 Base64 编码,再用 hmac.compare_digest 比较。命令行中,openssl dgst -sha256 -hmac 'key' -binary | base64 会得到同样的 Base64;密钥是 hex 时请用 -mac HMAC -macopt hexkey:…。要生成强密钥,可以用 Base64 密钥生成器 的 HMAC 密钥预设,它会生成 32 个随机字节。如果要签名的是令牌而不是请求,请看 JWT 编码器。

常见问题

为什么我的 Webhook HMAC 对不上?

签名覆盖的是请求体的确切字节。如果框架已经解析了 JSON,而你对重新序列化后的副本计算哈希,空格或键的顺序会变化,结果就不同。请对原始请求体计算哈希,确认服务方要求的是 hex 还是 Base64,并确认密钥是否需要先解码。

HMAC 密钥是文本还是 Base64?

取决于服务方。大多数给你的是一个按 UTF-8 文本使用的字符串。有些提供的是 Base64 编码的密钥,有时带有 whsec_ 之类的前缀,使用前必须解码为字节。请相应地设置 密钥格式。

哈希和 HMAC 有什么区别?

任何人都能计算一条消息的 SHA-256,所以哈希只能发现意外的改动。HMAC 混入了密钥,只有持有密钥的人才能生成有效的值,因此它是一种签名。

可以使用 HMAC-MD5 或 HMAC-SHA1 吗?

两者仍在一些老 API 中使用,而且比单纯的 MD5 或 SHA-1 强得多,因为碰撞并不能转化为 HMAC 伪造。新设计请选择 HMAC-SHA256。