使用 HMAC(Hash-based Message Authe
2025-07-03 本文已影响0人
_浅墨_
✅ HMAC 加密方式简介
HMAC 是一种基于哈希函数和密钥的消息认证码算法,常见如 HMAC-SHA256。它不是加密算法,而是用于生成一个固定长度的摘要,用来验证消息的完整性和真实性。
🔐 特点:
- 单向性:无法从 HMAC 结果反推原始数据。
- 依赖密钥:必须拥有相同的密钥才能验证 HMAC 的合法性。
- 防篡改:即使消息被修改,HMAC 也会校验失败。
🧩 在登录流程中如何使用 HMAC?
你可以结合 HMAC 实现如下流程:
1. 客户端
// 假设用户输入明文 password = "myPassword"
String salt = generateRandomSalt(); // 客户端随机生成盐值或 nonce
String hmac = HmacUtils.hmacSha256(password, salt + serverPublicKey); // 使用服务端公钥作为密钥
发送:
{
"username": "user",
"password": "hmacResultHere", // HMAC 处理后的字符串
"salt": "randomSaltValue" // 或者用时间戳、nonce
}
2. 服务端
// 获取用户信息中的原始密码(已加密存储)
String storedPassword = user.getPassword();
// 使用相同逻辑计算预期 HMAC
String expectedHmac = HmacUtils.hmacSha256(storedPassword, salt + serverPublicKey);
if (expectedHmac.equals(receivedHmac)) {
// 验证成功
}
🛡️ HMAC vs 加密(RSA/AES)
| 比较维度 | HMAC | RSA / AES(加密) |
|---|---|---|
| 是否可逆 | ❌ 不可逆 | ✅ 可以解密 |
| 是否需要密钥 | ✅ 需要共享密钥 | ✅ 需要管理密钥 |
| 抗重放攻击 | ❌ 需配合 nonce/salt 才能防御 | ✅ 更好 |
| 数据完整性验证 | ✅ 强项 | ❌ 不提供 |
| 密码比对方式 | 必须服务端参与比对 | 可在客户端加密后直接比对数据库 |
✅ 推荐组合方案(更安全)
✅ HTTPS + 前端加密(RSA)+ 后端验证 + HMAC 防重放攻击
流程图:
前端:
明文密码 + nonce → HMAC → base64(encrypted by RSA public key)
后端:
接收密文 → RSA 解密 → 校验 HMAC → 查询数据库对比密码
示例代码片段(伪代码):
@PostMapping("/login")
public AjaxResult authLogin(@RequestBody LoginBody loginBody) {
String decryptedPassword = RsaUtils.decrypt(loginBody.getPassword()); // 解密
String receivedNonce = loginBody.getNonce();
if (!HmacUtils.verify(decryptedPassword, receivedNonce, expectedKey)) {
throw new CustomException("HMAC validation failed");
}
String token = loginService.authLogin(loginBody.getUsername(), decryptedPassword);
return AjaxResult.success().put(Constants.TOKEN, token);
}
⚠️ 注意事项
- 避免日志记录密码字段,包括 HMAC 结果。
- 定期更新密钥(HMAC 和 RSA 公私钥)。
- 防止重放攻击:建议每次请求带唯一 nonce 或 timestamp,并缓存一段时间内拒绝重复使用。
- 密钥管理:推荐使用配置中心或 KMS(密钥管理系统)保存敏感信息。
✅ 总结
| 场景 | 是否适合 HMAC |
|---|---|
| 纯粹验证身份 | ✅ 可行,需配合 nonce/时间戳 |
| 密码传输 | ⚠️ 可用,但建议结合加密(如 RSA) |
| 安全性要求高 | ❌ 单独 HMAC 不够,应搭配其他机制 |
| 防篡改 | ✅ 推荐使用 HMAC |
✅ 最佳实践建议:
如果你希望提升安全性且支持现代 Web 安全标准,推荐使用:
- HTTPS + 前端 RSA 加密密码
- 后端解密并使用 BCryptPasswordEncoder 对比数据库密码
- 可选 HMAC 校验用于防篡改
这样既保证了传输安全,又提升了存储与验证的安全性。