HMAC 签名计算器
输入消息与密钥、选择算法,即可得到 HMAC 签名(小写十六进制放在主结果处,同时给出 Base64 形式),用于对接 API 鉴权、校验 Webhook 回调签名。计算全部在浏览器本地完成,密钥不经过服务器、不写入浏览器存储,也刻意不提供计算历史。
对接支付网关、开放平台或校验 Webhook 回调时,签名几乎都是 HMAC:把密钥混进哈希运算,不知道密钥就伪造不出签名——这是它与裸 SHA-256 的本质区别。本工具支持 SHA-256 / SHA-1 / MD5 三种算法,同时给出十六进制与 Base64 两种输出,覆盖各家接口文档的不同要求。
本地算的和服务端对不上是最高频问题,原因几乎总在三处:编码(本工具固定 UTF-8)、消息拼装(很多接口要求参数名字典序拼接或加时间戳,不是原始报文)、输出形式(Base64 还是大写十六进制)。排查时直接拿接口文档里的示例串算一遍,能对上说明算法对、错在拼装。
这个工具解决你的问题了吗?
提交后会把工具名、你的输入与当前结果发送到服务器;请勿填写身份证号、手机号等隐私信息。
AI 助手 会结合你当前的输入与结果回答
追问会再次把当前输入与结果发送到服务器;请勿填写隐私信息。
使用步骤
- 把服务端给的 Secret Key 填进密钥框。
- 把待签名内容粘进消息框——注意按接口文档要求拼装,不是原始报文。
- 选算法:新接口一律 HMAC-SHA256;老网关按文档选。
- 按服务端要求取十六进制或 Base64 形式比对。
计算原理与示例
基本用法
先在「密钥」里填入服务端给的 Secret Key,再把要签名的内容粘进消息框,签名即时生成。改任意一个字符(包括空格与换行)结果都会完全不同;密钥留空会提示错误,消息允许为空字符串。
为什么服务端算出来不一样
最常见的差异来自三处:一是编码,本工具统一按 UTF-8 处理,而有些服务端按 GBK 或先做 URL 编码;二是消息内容,很多接口要求的不是原始报文,而是「参数名按字典序拼接后的字符串」或「时间戳 + 随机串 + 报文」的组合;三是输出形式,服务端可能要求 Base64 或大写十六进制——比对前先确认这三项与服务端一致。
该选哪种算法
新接口一律用 HMAC-SHA256。HMAC-SHA1 只在对接 OAuth 1.0、老版本支付网关时保留;HMAC-MD5 只用于历史遗留接口。注意这里的「MD5 / SHA-1 不安全」指的是裸哈希碰撞,HMAC 加入了密钥,碰撞攻击不能直接套用,但既然有 SHA-256,没有理由在新接口上继续用旧算法。
计算口径:HMAC 按 RFC 2104 实现,哈希函数为 SHA-256、SHA-1(RFC 3174)与 MD5(RFC 1321);密钥与消息均按 UTF-8 编码后参与运算,密钥长度超过 64 字节时先摘要再补零到分组长度;输出为小写十六进制与标准 Base64。不做时间戳拼装、不做请求头拼装,也不做签名的常量时间校验。
代码示例
JavaScript Node 计算 HMAC
const { createHmac } = require("crypto");
createHmac("sha256", secret).update(payload).digest("hex");
createHmac("sha256", secret).update(payload).digest("base64");
// 服务端验签要用常量时间比较,防时序侧信道
crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));
PHP PHP 计算 HMAC
// 与多数国内支付网关文档写法一致
echo hash_hmac("sha256", $payload, $secret); // 十六进制
echo base64_encode(hash_hmac("sha256", $payload, $secret, true)); // Base64
// 注意:密钥超过 64 字节时 RFC 2104 规定先摘要再参与运算,
// hash_hmac 与本工具都已按此处理,无需手工截断
常见问题
HMAC 和直接做一次 SHA-256 有什么区别?
SHA-256 任何人都能算,攻击者改了消息就能重新算一个合法摘要;HMAC 把密钥混进计算,不知道密钥就伪造不出签名。所以校验接口来源用 HMAC,校验文件是否损坏才用裸哈希。另外 HMAC 是把密钥与消息做两轮哈希(内层异或 0x36、外层异或 0x5c),不是简单地「先哈希密钥再拼消息」。
密钥可以随便设多长吗?超过 64 字节会怎样?
没有硬性下限,但太短(比如 4 个字符)会被暴力猜出来,建议 32 字节以上随机串。密钥超过 64 字节(分组长度)时,HMAC 会先对密钥做一次摘要再参与运算——这是 RFC 2104 的规定;想验证这一点,可以用同一段消息分别配「64 字节密钥」和「80 字节密钥」算一次,本工具已把这两种情况做成示例。
签名结果是十六进制还是 Base64?
两者都对,取决于服务端约定。本工具主结果给 32 字节签名的小写十六进制(HMAC-SHA256 为 64 个字符),下方同时给出标准 Base64 形式。比对时注意大小写:有的服务端要求大写十六进制,可以用结果下方的形式转换后比对。
为什么同样的消息和密钥,我的结果和服务端对不上?
先查三处:编码(本工具固定 UTF-8)、消息原文(服务端常要求「按参数名排序后拼接」或「时间戳 + 随机串 + 报文」,不是原始报文)、输出形式(Base64 或大写十六进制)。接口文档里「签名算法」一节的示例串是最快的排查入口——照着文档给的示例值算一遍,能对上说明算法对、错在拼装。
时间戳为什么要放进签名内容里?
防重放:如果签名只覆盖业务参数,攻击者抓到一个合法请求就能原样重发。把时间戳(很多接口还会加随机串 nonce)纳入签名内容后,服务端可以拒绝超过 5~10 分钟的请求,重放窗口被压到极小。注意时间戳也属于消息内容,必须和服务端用同一格式(秒级还是毫秒级、是否补零)。
密钥会留在页面里或被上传吗?
不会。整段计算由浏览器本地完成,密钥不发送到服务器,也不写入浏览器存储,本工具刻意没有「计算历史」区块。即便如此,生产密钥(尤其带 sk_live 前缀的)仍建议只在测试环境用在线工具核对,正式环境交给代码或命令行。
HMAC-SHA1 的签名为什么只有 40 个字符?
因为 SHA-1 的摘要长度是 160 位 = 20 字节,十六进制就是 40 个字符;SHA-256 是 256 位 = 32 字节 = 64 个字符;MD5 是 128 位 = 16 字节 = 32 个字符。签名长度只反映摘要长度,不代表强度等级越高就越「多占」什么——真正的差别是抗碰撞能力。
能做「验证签名」而不只是生成吗?
本页只负责生成。验证的完整做法是:服务端收到请求后,用同样的密钥与消息算一遍 HMAC,再与你传来的签名比对。比对时要用**常量时间比较**(如 Node 的 crypto.timingSafeEqual),普通字符串比较会因为提前返回而泄漏信息、给攻击者留下爆破签名的旁路。
延伸阅读
来自本站原创文章,讲清这个工具背后的算法与口径。