密钥管理策略
密钥分层架构
密钥层次结构:
┌─────────────────────────────────┐
│ 主密钥(KEK - Key Encryption Key) │
│ 存储在KMS/HSM中,保护DEK │
└─────────────────────────────────┘
↓ 加密
┌─────────────────────────────────┐
│ 数据加密密钥(DEK - Data Encryption Key)│
│ 加密实际业务数据,由KEK保护 │
└─────────────────────────────────┘
↓ 加密
┌─────────────────────────────────┐
│ 用户敏感数据 │
│ 如手机号、收货地址、身份证号等 │
└─────────────────────────────────┘
核心概念
| 概念 | 说明 |
|---|---|
| KEK | 密钥加密密钥,保护DEK |
| DEK | 数据加密密钥,加密业务数据 |
| IV/Nonce | 初始化向量,保证加密唯一性 |
密钥管理服务(KMS)
推荐方案:
| 服务类型 | 适用场景 |
|---|---|
| 云厂商KMS | AWS KMS、阿里云KMS、腾讯云KMS |
| 开源方案 | HashiCorp Vault |
| 硬件安全模块 | HSM设备,最高安全级别 |
KMS核心功能:
- 密钥生成与存储
- 密钥轮换
- 访问控制(IAM/RBAC)
- 操作审计日志
密钥缓存策略
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())
);
}
}密钥轮换策略
双密钥期策略
密钥轮换流程:
时间线 →
┌──────────┬──────────┬──────────┐
│ 密钥v1 │ 密钥v1/v2 │ 密钥v2 │
│ 活跃期 │ 过渡期 │ 活跃期 │
└──────────┴──────────┴──────────┘
│ │ │
│ 新数据 │ 新数据 │ 新数据
│ 用v1加密 │ 用v2加密 │ 用v2加密
│ │ 旧数据 │ 旧数据
│ │ 读时升级 │ 已全部升级
└───────────┴───────────┘
懒重加密模式
优点:避免全量重加密的性能开销
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;
}
}轮换周期建议
| 密钥类型 | 建议轮换周期 |
|---|---|
| 主密钥(KEK) | 90-180天 |
| 数据密钥(DEK) | 30-90天 |
| 临时密钥 | 会话结束即销毁 |
安全要点
- 禁止硬编码密钥:密钥必须存储在KMS或配置中心
- 禁止重复使用IV:每个加密操作必须使用新IV
- 加密前后校验:防止数据篡改
- 密钥访问审计:记录所有密钥操作
面试要点
常见面试问题
Q:密钥为什么要分层管理?
A:分层管理降低风险:即使DEK泄露,攻击者仍无法获取KEK,从而无法解密其他数据。
Q:如何处理密钥轮换期间的数据访问?
A:采用双密钥期策略,保留当前和上一代密钥,新数据用新密钥加密,旧数据在访问时懒升级。
参考链接
- 数据加密-AES-GCM — AES-GCM 加密算法详解
- 数据加密与密钥管理 — 加密与密钥管理知识地图(MOC)
- 瑞幸后端-Q4-用户数据加密存储与密钥管理