技术问答整理
1. Java HMAC签名验签示例
问题
如何用Java实现HMAC签名和验签?
答案
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.HexFormat;
public class HmacExample {
// 生成HMAC签名(HmacSHA256 + Hex编码)
public static String generateHmac(String message, String key) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(secretKey);
byte[] hmacBytes = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
return HexFormat.of().formatHex(hmacBytes);
}
// 验证HMAC签名
public static boolean verifyHmac(String message, String key, String receivedSignature) throws Exception {
return generateHmac(message, key).equals(receivedSignature);
}
}
关键点:
- 算法选择:
HmacSHA256
/HmacSHA512
- 编码统一:UTF-8处理字符串
- 密钥安全:避免硬编码,使用密钥生成器
// 安全密钥生成示例
KeyGenerator keyGen = KeyGenerator.getInstance("HmacSHA256");
keyGen.init(256); // 256位密钥
byte[] key = keyGen.generateKey().getEncoded();
2. HMAC算法描述
问题
HMAC算法如何工作?有哪些核心特性?
答案
定义:
HMAC(Hash-based Message Authentication Code)是基于哈希函数的消息认证码,用于验证数据完整性和真实性。
公式:
[ \text{HMAC}(K, M) = H\left( (K \oplus \text{opad}) \parallel H\left( (K \oplus \text{ipad}) \parallel M \right) \right) ]
特性:
- 抗碰撞性:依赖哈希函数(如SHA-256)
- 密钥依赖:安全性要求密钥保密
- 应用场景:API签名、JWT令牌、文件校验
哈希算法对比:
算法 | 输出长度 | 安全性建议 |
---|---|---|
HmacSHA256 | 256位 | ✅ 推荐使用 |
HmacSHA512 | 512位 | ✅ 高安全场景 |
HmacSHA1 | 160位 | ⚠️ 仅兼容旧系统 |
3. 重放攻击防御
问题
如何通过时间戳和Nonce防御重放攻击?
答案
防御机制:
时间戳
- 客户端在请求中添加当前时间戳
- 服务端校验时间窗口(如±5分钟)
long timestamp = System.currentTimeMillis() / 1000; if (Math.abs(currentTime - timestamp) > 300) { /* 拒绝请求 */ }
Nonce(一次性随机数)
- 客户端生成唯一Nonce(如UUID)
- 服务端缓存已用Nonce,拒绝重复值
String nonce = UUID.randomUUID().toString(); if (redisCache.exists(nonce)) { /* 拒绝请求 */ }
联合防御:
- 时间戳解决历史请求重放
- Nonce解决即时重放
- 两者需参与HMAC签名计算
4. 挑战-响应机制
问题
挑战-响应机制如何实现身份验证?
答案
核心流程:
- 客户端发起认证请求
- 服务端返回随机挑战值(Challenge)
- 客户端用密钥生成响应(Response)
- 服务端验证响应合法性
实现方式:
- 对称加密(HMAC)
// 响应生成:HMAC(Challenge, SecretKey) String response = HmacExample.generateHmac(challenge, key);
- 非对称加密(数字签名)
// 客户端用私钥签名 Signature sig = Signature.getInstance("SHA256withRSA"); sig.initSign(privateKey); byte[] signature = sig.sign();
应用场景:
- OAuth 2.0 PKCE:
code_verifier
和code_challenge
- SSH登录:服务器发送加密挑战,客户端用私钥解密