1 简介
HMAC(基于哈希的消息认证码)是一种消息认证码(MAC),通过对要认证的数据和秘密共享密钥执行加密哈希函数来获取。与任何 MAC 一样,它用于数据完整性和身份验证。

HMAC(基于哈希的消息认证码)是一种加密技术,它使用哈希函数和密钥来确保数据的完整性和真实性。与基于签名和非对称密码学的方法不同。HMAC 的 公式非常容易理解:
ini
HMAC = hashFunc(secret key + message)
检查数据完整性对于参与通信的各方来说是必要的。HTTPS、SFTP、FTPS 和其他传输协议都可以使用 HMAC。加密哈希函数可以是 MD-5、SHA-1 或 SHA-256。
数字签名几乎与 HMAC 相似,即它们都采用哈希函数和共享密钥。区别在于密钥,即 HMAC 使用对称密钥(同一副本),而签名使用非对称密钥(两个不同的密钥)。
2 在Rest API 场景中的签名生成
有三种类型的身份验证功能。它们是消息加密、消息验证码和哈希函数。
MAC 和哈希(这里是 HMAC)之间的主要区别在于密钥的依赖性。
在 HMAC 中,我们必须在纯文本上应用哈希函数和键。哈希函数将应用于纯文本消息。但在应用之前,我们必须计算 S 位,然后将其附加到纯文本中,然后应用哈希函数。为了生成这些 S 位,我们使用发送方和接收方之间共享的密钥。
示例:按参数排序拼接,假设你的签名消息是把排序后的参数名和值直接拼成 key1value1key2value2...,要用 HMAC-SHA256 做签名,Go 示例:
go
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"sort"
"strings"
)
func SignParamsHMACSHA256(params map[string]string, secret string) string {
// 1. 排序 keys
keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
// 2. 连接 key+value
var sb strings.Builder
for _, k := range keys {
sb.WriteString(k)
sb.WriteString(params[k])
}
message := []byte(sb.String())
// 3. HMAC-SHA256
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(message)
sig := mac.Sum(nil)
// 4. 输出 hex 大写(或按接口约定)
return strings.ToUpper(hex.EncodeToString(sig))
}
注意:如果你之前的协议是 sha1(appSecret + concatenation + appSecret),改用 HMAC 会生成不同结果------必须客户端/服务端同一套约定。
3 Go 演示输出(样例并给出结果)
下面是两组示例(我在分析里验证过输出)。示例输出(全部为大写 hex):
ini
key = "secretkey",message = "The quick brown fox jumps over the lazy dog"
→ HMAC-SHA256(HEX 大写):
markdown
033D11A367048B3748B5FF62776B23263681FA30B4AB6B188BB249080044BCBF
message = (把字段拼接成的字符串,例如之前的推送拼接结果)
→ HMAC-SHA256(HEX 大写):
markdown
FA591B27098AEDAB0B019DECB0D3704903FD81B2B502BD5EA2A38DCBAD7EDFEA
(提示:实际签名需保证字符编码一致(UTF-8)、参数排序规则完全一致、以及是否包含 appKey/timestamp 等都必须和服务端一致。)
-
与"对称算法"(如 AES)的主要不同点(对比表)
css特性 HMAC-SHA256(消息认证码) 对称加密(例如 AES) 目的 完整性 & 认证:确保消息未被篡改并且来自持有密钥的一方 保密性:确保消息内容不可被未授权方读取 可逆性 不可逆(MAC) --- 输出固定长度的标识,不能从 MAC 恢复消息或密钥 可逆(解密) --- 解密能恢复原始明文(需要密钥/IV) 输入 / 输出 输入任意长度消息 → 输出固定长度 MAC(32 字节 for SHA-256) 输入明文 → 输出密文(长度≈明文长度 + padding/IV) 使用密钥 使用共享密钥(对称),用于计算 MAC(不可用于"解密") 使用共享密钥进行加密/解密 防篡改 是(用于检测篡改) 默认不保证完整性(通常需要 AEAD 模式如 AES-GCM 才同时保证机密性和完整性) 典型用途 API 签名、消息认证、token 完整性 存储加密、传输加密(如果用 TLS、或 AES-GCM 作为 AEAD) 计算成本 一次或两次哈希运算(很快) 块密码运算 + 可能的模式开销(现代 CPU 有 AES 指令加速)
4 小结
HMAC 用来证明消息是完整且来自密钥持有方;对称加密用来隐藏消息内容。两者通常结合使用(例如:先加密再用 HMAC 签名,或使用 AEAD 模式同时提供两者)。
(在 API 场景)使用 crypto/hmac + sha256(或更强的 sha512)进行消息签名。
签名时用稳定的"规范化"流程:统一字符编码(UTF-8)、参数名大小写、排序规则、空值处理(忽略/当空串)等。
用 hmac.Equal 做常量时间比较,避免时序泄露。
加入 timestamp / nonce / replay window(如 ±5 分钟)防止重放攻击。
建议密钥长度至少 256 位(32 字节),并定期轮换。
如果既要保密又要认证,优先使用 AEAD(例如 AES-GCM 或使用 TLS),或"先加密后签名"且管理好 IV/nonce。