本文目录
什么是 HMAC?
HMAC(基于哈希的消息认证码)是一种密码学机制,它将密钥与哈希函数结合起来,生成一段消息认证码。与普通哈希不同,HMAC 能同时证明消息的完整性和真实性——它可以告诉你数据未被篡改,并且确实来自知道该密钥的一方。
HMAC 在 RFC 2104 中定义,广泛应用于 TLS、IPsec、JWT 签名以及 API webhook 验证。该算法能够抵御长度扩展攻击,而 SHA-256 等普通哈希函数则易受此类攻击影响,因此 HMAC 成为带密钥消息认证的标准选择。
HMAC 的工作原理
HMAC 采用带内层与外层填充的两轮哈希方法。首先将密钥填充至哈希函数的分组大小,再分别与两个不同的常量(ipad 和 opad)进行异或,从而派生出两把密钥。
- 内层哈希——将密钥与 ipad(重复的 0x36)异或,拼接上消息后进行哈希:H(K XOR ipad || message)
- 外层哈希——将密钥与 opad(重复的 0x5C)异或,拼接上内层哈希结果后再次进行哈希:H(K XOR opad || inner_hash)
- 最终输出——外层哈希的结果即为 HMAC 值,通常以十六进制字符串表示
这种双重哈希结构可以防止长度扩展攻击。即使攻击者知道 H(message),在没有密钥的情况下也无法计算出 HMAC(key, message || extra_data)。
HMAC 算法
HMAC 结构可与任意密码学哈希函数配合使用。最常用的是 SHA-256、SHA-384 和 SHA-512,尽管 SHA-1 和 MD5 仍存在于一些遗留系统中。
- HMAC-SHA256——256 位输出,是 API 认证、JWT HS256 签名和 webhook 验证中应用最广泛的变体。推荐密钥长度:32 字节
- HMAC-SHA384——384 位输出,用于 TLS 1.3 加密套件及高安全性场景。推荐密钥长度:48 字节
- HMAC-SHA512——512 位输出,在需要最大安全裕度或平台能够高效处理 64 位运算时首选。推荐密钥长度:64 字节
密钥长度至少应与哈希输出长度相当。过短的密钥会被填充,过长的密钥则会先被哈希。对于大多数应用而言,采用 32 字节随机密钥的 HMAC-SHA256 已能提供出色的安全性。
免费试用 —— 无需注册
生成 HMAC 签名 →常见使用场景
HMAC 是众多安全协议和 API 认证方案的基础。
- API 认证——Stripe、GitHub 和 AWS 等服务使用 HMAC 签名来验证 webhook 载荷,确保请求确实来自服务提供方
- JWT 签名——JSON Web Token 中的 HS256、HS384 和 HS512 算法使用 HMAC 对令牌载荷进行签名,使接收方能够验证令牌未被修改
- 消息完整性——HMAC 用于验证通过网络传输的数据在传输过程中未被更改,应用于 TLS 记录层和 IPsec 认证头
- OAuth 1.0a——HMAC-SHA1 签名方法对 OAuth 请求参数进行签名,以证明该请求来自已授权的客户端
HMAC 与其他认证方法的对比
HMAC 是消息认证的多种方案之一。每种方案在安全性、性能和密钥管理方面各有取舍。
- HMAC 与数字签名——HMAC 使用共享密钥(对称),而数字签名使用公钥/私钥对(非对称)。HMAC 速度更快,但要求双方共享同一密钥;数字签名则提供不可否认性。
- HMAC 与 API 密钥——API 密钥只是通过请求头发送的简单持有者令牌。HMAC 会对请求内容进行签名,因此即便截获了之前的某个请求,也无法据此伪造新请求。当结合时间戳或随机数(nonce)使用时,HMAC 还能提供重放保护。
- HMAC 与普通哈希——用 SHA-256 对消息做哈希只能证明完整性,无法证明真实性,因为任何人都能计算 SHA-256(message)。HMAC 需要密钥,只有获得授权的一方才能生成有效签名。
常见问题
理想的 HMAC 密钥长度是多少?
密钥长度至少应与哈希输出长度相当——HMAC-SHA256 为 32 字节,HMAC-SHA384 为 48 字节,HMAC-SHA512 为 64 字节。短于哈希输出的密钥会削弱安全保障。长于分组大小的密钥(SHA-256 为 64 字节,SHA-512 为 128 字节)会先被哈希,因此使用超长密钥并无额外益处。
HMAC 和加密是一回事吗?
不是。HMAC 提供的是认证与完整性,而非机密性。HMAC 签名能够证明消息未被篡改、由掌握密钥的一方生成,但原始消息本身仍然可读。如果你需要隐藏消息内容,应在使用 HMAC 之外再采用加密(如 AES、ChaCha20)。
我能在浏览器中通过 Web Crypto API 使用 HMAC 吗?
可以。Web Crypto API 通过 crypto.subtle.importKey() 和 crypto.subtle.sign() 原生支持 HMAC。你无需任何外部库,即可完全在客户端生成 HMAC-SHA256、HMAC-SHA384 和 HMAC-SHA512 签名。现代基于浏览器的 HMAC 工具正是采用这一方式。