正在加载,请稍候…

HMAC 详解:使用密钥进行消息认证

了解 HMAC 是什么、它与普通哈希有何不同,以及何时将其用于 API 认证和数据完整性验证。

HMAC 详解:使用密钥进行消息认证

什么是 HMAC?

HMAC(基于哈希的消息认证码)是一种特定类型的消息认证码,它结合了密码学哈希函数和密钥。它融合了哈希函数(数据完整性)和共享密钥(真实性)的能力,在单个紧凑输出中同时提供两者。

HMAC 在 RFC 2104 中标准化,广泛应用于从 AWS 请求签名到 GitHub 和 Stripe 的 webhook 验证等场景。

HMAC 详解:使用密钥进行消息认证 插图

为什么不直接对消息进行哈希?

如果仅对消息进行哈希并将两者一起发送,攻击者可以:

  1. 拦截消息和哈希值。
  2. 修改消息。
  3. 计算修改后消息的新哈希值。
  4. 替换两者——接收方无法检测到篡改。

HMAC 可以防止这种情况,因为计算有效的 MAC 需要密钥。没有密钥,攻击者无法为修改后的消息伪造有效的 MAC。

HMAC 的工作原理

HMAC(K, m) = H((K' ⊕ opad) || H((K' ⊕ ipad) || m))

其中:

  • H = 哈希函数(SHA-256、SHA-512 等)
  • K = 密钥(填充到块大小作为 K')
  • m = 消息
  • opad = 外部填充(0x5c 重复)
  • ipad = 内部填充(0x36 重复)

密钥被处理两次:一次混合到内部哈希中,另一次混合到外部哈希中。这种双重密钥结构可以防止影响普通哈希的长度扩展攻击。

HMAC 与普通哈希对比

属性 普通哈希 HMAC
需要密钥
完整性验证
真实性验证
无需密钥即可伪造
抗长度扩展 ❌ (SHA-2)

HMAC 详解:使用密钥进行消息认证 插图

为 HMAC 选择哈希算法

HMAC 变体 安全性 常见用途
HMAC-MD5 仅限遗留系统
HMAC-SHA1 可接受 Git、旧协议
HMAC-SHA256 ✅ 强 AWS Signature V4、大多数 API
HMAC-SHA512 ✅ 非常强 高安全要求

HMAC-SHA256 是大多数应用的现代标准。

实际应用中的 HMAC

Webhook 签名验证

当 GitHub、Stripe 或 Shopify 向你的服务器发送 webhook 时,它们会在请求头中包含 HMAC 签名。你通过使用密钥计算请求体的 HMAC 并进行比较来验证它。

// 验证 GitHub webhook
const crypto = require('crypto');

function verifySignature(secret, payload, signature) {
  const computed = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(computed),
    Buffer.from(signature)
  );
}

注意使用 timingSafeEqual——逐字符比较 MAC 值会泄露攻击者可利用的时序信息。始终使用常量时间比较。

HMAC 详解:使用密钥进行消息认证 插图

AWS Signature Version 4

每个 AWS API 请求都使用 HMAC-SHA256 签名,密钥由你的秘密访问密钥派生而来:

SigningKey = HMAC(HMAC(HMAC(HMAC("AWS4" + SecretKey, Date), Region), Service), "aws4_request")
Signature = HMAC(SigningKey, StringToSign)

这种多级派生意味着即使某个请求的签名密钥意外暴露,也无法用于签署其他日期、区域或服务的请求。

JWT HS256 签名

当 JWT 使用 HS256 算法时,它使用 HMAC-SHA256 签名:

const signature = HMAC_SHA256(secret, base64url(header) + '.' + base64url(payload));

Cookie 和会话完整性

Express.js 等框架使用 HMAC 签名 cookie 以防止篡改:

// Express cookie-session 内部使用 HMAC
app.use(session({
  secret: 'your-secret-key',  // 用于 HMAC 签名
  resave: false,
  saveUninitialized: true
}));

安全注意事项

  1. 密钥长度——对于 HMAC-SHA256 密钥,至少使用 32 字节(256 位)。
  2. 密钥轮换——定期轮换 HMAC 密钥。轮换时,支持一个短暂的过渡窗口,新旧密钥同时有效。
  3. 常量时间比较——始终在常量时间内比较 MAC,以防止时序攻击。
  4. 密钥存储——切勿在源代码中硬编码 HMAC 密钥。使用环境变量或密钥管理器。

使用此工具

输入你的消息和密钥,选择哈希算法(MD5、SHA-1、SHA-256、SHA-384、SHA-512),工具将在浏览器中计算 HMAC。你可以将结果输出为十六进制(默认)、Base64 或 Base64URL 格式。

→ 尝试 HMAC 生成器