数据加密与密钥管理
一、加密方案选择
1.1 AES-GCM 模式
推荐用于用户敏感数据加密(如手机号、收货地址)
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
public class AesGcmEncryption {
private static final int GCM_IV_LENGTH = 12; // 推荐12字节
private static final int GCM_TAG_LENGTH = 128; // 认证标签长度
// 加密
public byte[] encrypt(byte[] data, byte[] key) throws Exception {
byte[] iv = new byte[GCM_IV_LENGTH];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), spec);
byte[] encrypted = cipher.doFinal(data);
// IV + 密文
byte[] result = new byte[iv.length + encrypted.length];
System.arraycopy(iv, 0, result, 0, iv.length);
System.arraycopy(encrypted, 0, result, iv.length, encrypted.length);
return result;
}
// 解密
public byte[] decrypt(byte[] encryptedData, byte[] key) throws Exception {
byte[] iv = new byte[GCM_IV_LENGTH];
byte[] ciphertext = new byte[encryptedData.length - GCM_IV_LENGTH];
System.arraycopy(encryptedData, 0, iv, 0, GCM_IV_LENGTH);
System.arraycopy(encryptedData, GCM_IV_LENGTH, ciphertext, 0, ciphertext.length);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), spec);
return cipher.doFinal(ciphertext);
}
}1.2 AES-GCM 优势
| 特性 | 说明 |
|---|---|
| 加密+认证 | 自带消息认证码(MAC),防止篡改 |
| 安全性高 | 防止填充Oracle攻击,比CBC模式更安全 |
| 效率高 | 并行加密,性能优于其他模式 |
1.3 IV(初始化向量)要点
- 唯一性:每个加密操作必须使用唯一IV
- 随机性:使用
SecureRandom生成 - 存储:IV与密文一起存储(不需要保密)
- 长度:推荐12字节(96位),兼顾安全性和性能
二、密钥管理策略
2.1 密钥分层架构
密钥层次结构:
┌─────────────────────────────────┐
│ 主密钥(KEK - Key Encryption Key) │
│ 存储在KMS/HSM中,保护DEK │
└─────────────────────────────────┘
↓ 加密
┌─────────────────────────────────┐
│ 数据加密密钥(DEK - Data Encryption Key)│
│ 加密实际业务数据,由KEK保护 │
└─────────────────────────────────┘
↓ 加密
┌─────────────────────────────────┐
│ 用户敏感数据 │
│ 如手机号、收货地址、身份证号等 │
└─────────────────────────────────┘
2.2 密钥管理服务(KMS)
推荐方案:
| 服务类型 | 适用场景 |
|---|---|
| 云厂商KMS | AWS KMS、阿里云KMS、腾讯云KMS |
| 开源方案 | HashiCorp Vault |
| 硬件安全模块 | HSM设备,最高安全级别 |
KMS核心功能:
- 密钥生成与存储
- 密钥轮换
- 访问控制(IAM/RBAC)
- 操作审计日志
2.3 密钥缓存策略
public class KeyCacheManager {
private final Map<String, byte[]> keyCache = new ConcurrentHashMap<>();
private final KmsClient kmsClient;
private static final long CACHE_TTL = 30 * 60 * 1000; // 30分钟
public byte[] getKey(String keyId) {
String cacheKey = keyId + "_" + getCurrentKeyVersion(keyId);
return keyCache.computeIfAbsent(cacheKey, k -> {
try {
return kmsClient.decryptKey(keyId);
} catch (Exception e) {
throw new RuntimeException("Failed to get key from KMS", e);
}
});
}
// 定期清理过期缓存
@Scheduled(fixedRate = 60000)
public void cleanupCache() {
keyCache.entrySet().removeIf(entry ->
isExpired(entry.getKey())
);
}
}三、密钥轮换策略
3.1 双密钥期策略
密钥轮换流程:
时间线 →
┌──────────┬──────────┬──────────┐
│ 密钥v1 │ 密钥v1/v2 │ 密钥v2 │
│ 活跃期 │ 过渡期 │ 活跃期 │
└──────────┴──────────┴──────────┘
│ │ │
│ 新数据 │ 新数据 │ 新数据
│ 用v1加密 │ 用v2加密 │ 用v2加密
│ │ 旧数据 │ 旧数据
│ │ 读时升级 │ 已全部升级
└───────────┴───────────┘
3.2 懒重加密模式
优点:避免全量重加密的性能开销
public class LazyReEncryptionService {
public String decryptAndUpgradeIfNeeded(String encryptedData, String currentKeyId) {
// 1. 获取加密时使用的密钥版本
String encryptionKeyId = extractKeyIdFromData(encryptedData);
// 2. 解密数据
byte[] key = keyManager.getKey(encryptionKeyId);
String plaintext = decrypt(encryptedData, key);
// 3. 如果不是最新密钥,进行升级
if (!encryptionKeyId.equals(currentKeyId)) {
byte[] newKey = keyManager.getKey(currentKeyId);
String reEncrypted = encrypt(plaintext, newKey);
// 异步更新数据库
asyncUpdateData(encryptedData, reEncrypted);
}
return plaintext;
}
}3.3 轮换周期建议
| 密钥类型 | 建议轮换周期 |
|---|---|
| 主密钥(KEK) | 90-180天 |
| 数据密钥(DEK) | 30-90天 |
| 临时密钥 | 会话结束即销毁 |
四、国密算法支持(SM4)
国内合规要求时使用
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;
public class SM4Encryption {
static {
Security.addProvider(new BouncyCastleProvider());
}
public byte[] encryptSM4Gcm(byte[] data, byte[] key, byte[] iv) throws Exception {
Cipher cipher = Cipher.getInstance("SM4/GCM/NoPadding", "BC");
GCMParameterSpec spec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "SM4"), spec);
return cipher.doFinal(data);
}
}五、面试要点
5.1 核心概念
| 概念 | 说明 |
|---|---|
| 对称加密 | 加密解密使用相同密钥(AES、SM4) |
| 非对称加密 | 加密解密使用不同密钥(RSA) |
| KEK | 密钥加密密钥,保护DEK |
| DEK | 数据加密密钥,加密业务数据 |
| IV/Nonce | 初始化向量,保证加密唯一性 |
5.2 安全要点
- 禁止硬编码密钥:密钥必须存储在KMS或配置中心
- 禁止重复使用IV:每个加密操作必须使用新IV
- 加密前后校验:防止数据篡改
- 密钥访问审计:记录所有密钥操作
5.3 常见面试问题
Q:为什么推荐AES-GCM而不是CBC?
A:GCM模式自带认证功能,能检测数据是否被篡改,且避免了CBC模式的填充Oracle攻击风险。
Q:密钥为什么要分层管理?
A:分层管理降低风险:即使DEK泄露,攻击者仍无法获取KEK,从而无法解密其他数据。
Q:如何处理密钥轮换期间的数据访问?
A:采用双密钥期策略,保留当前和上一代密钥,新数据用新密钥加密,旧数据在访问时懒升级。