4、密钥分类与策略:对称密钥与非对称密钥策略、会话密钥与主密钥策略、密钥用途约束
密钥管理这件事,说白了就是回答三个问题:用什么密钥?怎么用?用在哪? 我在做HSM项目时,见过太多因为密钥分类不清导致的权限泄露事故。这一章,我们就来把这些策略彻底理清楚。
核心原则:密钥分类不是学术分类,而是安全策略的基石。分类错了,策略就形同虚设。
4.1 对称密钥与非对称密钥策略
先看一个最基础的分类。HSM里存的密钥,要么是对称的,要么是非对称的。但它们的策略完全不同。
| 维度 | 对称密钥 | 非对称密钥 |
|---|---|---|
| 典型算法 | AES-256, SM4, 3DES | RSA-4096, ECC P-384, SM2 |
| HSM存储方式 | 密钥值直接存储在安全区内 | 私钥存储在安全区,公钥可导出 |
| 导出策略 | 默认禁止导出(wrap/unwrap除外) | 私钥禁止导出,公钥可自由导出 |
| 备份策略 | 必须加密后备份,且与密钥标签绑定 | 私钥备份需双人控制,公钥无需备份 |
| 生命周期 | 较短(通常1-2年) | 较长(通常3-5年) |
我个人习惯,在HSM里给对称密钥和非对称密钥分配不同的密钥槽(Key Slot)区域。比如,槽位1-100只放对称密钥,槽位101-200只放非对称密钥对。这样策略配置时,可以直接按槽位范围批量下发,不容易出错。
经验之谈:我曾经在一个金融项目中,客户把AES密钥和RSA私钥混放在同一个密钥组里。结果审计时发现,一个本该只能做加密的AES密钥,因为策略继承问题,被误配了解密权限。从那以后,我坚持物理隔离——不同类别的密钥,必须放在不同的密钥容器中。
4.1.1 对称密钥策略要点
- 密钥用途必须单一:一个AES密钥要么只做加密,要么只做解密,不要同时赋予两种用途。你想想看,如果加密密钥被用来解密,那加密的意义何在?
- 密钥版本管理:对称密钥更新时,旧密钥必须保留一段时间用于解密旧数据,但不能再用于加密新数据。这个策略叫"加密用新钥,解密兼容旧"。
- 密钥轮换周期:我建议对称密钥最长使用不超过2年。如果业务量巨大,比如每秒处理上万笔交易,那半年轮换一次都不为过。
4.1.2 非对称密钥策略要点
- 私钥永不离开HSM:这是铁律。任何试图导出私钥的操作,都应该被HSM的策略引擎直接拒绝。我在项目中遇到过有人想用wrap机制把私钥包出去做备份,被我当场叫停——私钥一旦离开HSM的物理边界,就不再是安全的了。
- 公钥可以导出,但需要签名:公钥导出时,最好由HSM内的签名密钥对公钥进行签名,防止公钥在传输过程中被篡改。
- 密钥用途分离:签名密钥对和加密密钥对必须分开。不要用同一对RSA密钥既做签名又做加密。为什么?因为签名需要私钥,加密需要公钥,如果混用,攻击者可能利用签名预言机来破解加密数据。
4.2 会话密钥与主密钥策略
这是另一个容易混淆的地方。很多初学者分不清会话密钥和主密钥的区别。我打个比方:主密钥是你家的保险柜,会话密钥是保险柜里取出来的一次性信封。
定义:主密钥(Master Key)是长期存储在HSM中的根密钥,用于保护其他密钥。会话密钥(Session Key)是临时生成的,用于保护一次通信会话中的数据。
4.2.1 主密钥策略
- 主密钥必须由HSM内部生成:绝对不能从外部导入。我记得有一次,客户想从软件里生成一个主密钥再导入HSM,我直接拒绝了——主密钥一旦在软件中出现过,就可能被内存抓取工具窃取。
- 主密钥的备份必须采用密钥分割(Key Splitting):比如把主密钥分成5份,分别交给5个管理员保管,恢复时需要至少3份。这就是所谓的M of N控制。
- 主密钥的用途极其有限:通常只用于解密下一层级的密钥加密密钥(KEK),或者用于验证HSM自身的完整性。它不应该直接参与业务数据的加解密。
4.2.2 会话密钥策略
- 会话密钥必须是一次一密:每次会话结束后,会话密钥必须立即销毁。HSM应该提供显式的"销毁会话密钥"API调用。
- 会话密钥的生成必须基于主密钥:通常是通过主密钥派生(Key Derivation)得到,而不是独立随机生成。这样做的目的是:只要主密钥安全,所有派生出的会话密钥都可追溯、可审计。
- 会话密钥的生命周期极短:一般不超过24小时。如果是实时通信场景,比如TLS握手,会话密钥的生命周期可能只有几分钟。
| 对比项 | 主密钥 | 会话密钥 |
|---|---|---|
| 生命周期 | 数年 | 分钟到小时 |
| 存储位置 | HSM永久存储区 | HSM临时内存区 |
| 生成方式 | HSM内部硬件生成 | 主密钥派生或随机生成 |
| 导出策略 | 绝对禁止导出 | 可导出(但需加密保护) |
| 备份策略 | M of N分割备份 | 不备份,用完即毁 |
避坑指南:我曾经在一个项目中,开发团队为了性能优化,把会话密钥的生命周期设置成了7天。结果第3天,一个会话密钥被攻击者从内存中抓取,导致过去7天的所有通信数据都被解密。教训是什么?会话密钥的生命周期越短越好,不要为了性能牺牲安全。
4.3 密钥用途约束
这是HSM策略中最容易被忽视,但也是最重要的一环。密钥用途约束,说白了就是给每把钥匙规定好它能开哪把锁。
HSM通常支持以下用途约束:
- encrypt/decrypt:仅用于加解密数据
- sign/verify:仅用于签名和验签
- wrap/unwrap:仅用于密钥的封装和解封
- derive:仅用于密钥派生
- mac/generate:仅用于消息认证码的生成和验证
我个人的做法是:每个密钥在创建时,必须明确指定用途,且用途数量不超过2个。 如果一个密钥同时拥有encrypt、decrypt、sign、verify四个用途,那它就是一个定时炸弹。
实用技巧:在配置HSM策略时,可以创建一个"用途矩阵",横轴是密钥ID,纵轴是用途,交叉点打勾表示允许。这样一目了然,审计时也方便。我参与过的几个大型项目,都是靠这个矩阵通过的安全审计。
4.3.1 用途约束的常见陷阱
- 陷阱一:wrap密钥同时拥有encrypt用途。 这意味着攻击者可以用wrap密钥加密任意数据,然后假装是密钥块导出。我曾经见过一个案例,就是因为wrap密钥被赋予了encrypt权限,导致攻击者把恶意数据伪装成密钥块导出了HSM。
- 陷阱二:签名密钥同时拥有verify用途。 这看起来合理,但实际上,如果签名密钥可以验签,攻击者就可以用暴力方式猜测签名值。正确的做法是:签名密钥只做sign,验签用独立的verify密钥。
- 陷阱三:主密钥被赋予了derive用途之外的权限。 主密钥应该只做derive,其他用途一律禁止。否则,一旦主密钥被滥用,整个密钥体系都会崩塌。
4.4 密钥分类与策略全景图
下面这张图,是我在项目中总结的密钥分类与策略关系图。它清晰地展示了不同密钥类型、生命周期、用途约束之间的关联。
4.5 实战策略配置示例
最后,我给出一个实际的HSM策略配置片段。这是我在一个支付项目中用过的配置,你可以参考。
# HSM密钥策略配置示例(PKCS#11风格)
# 密钥A:主密钥(仅用于派生)
CKA_CLASS = CKO_SECRET_KEY
CKA_KEY_TYPE = CKK_AES
CKA_VALUE_LEN = 32
CKA_TOKEN = TRUE
CKA_PRIVATE = TRUE
CKA_EXTRACTABLE = FALSE
CKA_DERIVE = TRUE
CKA_ENCRYPT = FALSE
CKA_DECRYPT = FALSE
CKA_WRAP = FALSE
CKA_UNWRAP = FALSE
CKA_SIGN = FALSE
CKA_VERIFY = FALSE
# 密钥B:会话密钥(仅用于加密,由主密钥派生)
CKA_CLASS = CKO_SECRET_KEY
CKA_KEY_TYPE = CKK_AES
CKA_VALUE_LEN = 16
CKA_TOKEN = FALSE # 会话密钥,不持久化
CKA_PRIVATE = TRUE
CKA_EXTRACTABLE = FALSE
CKA_DERIVE = FALSE
CKA_ENCRYPT = TRUE
CKA_DECRYPT = FALSE # 仅加密,不解密
CKA_WRAP = FALSE
CKA_UNWRAP = FALSE
CKA_SIGN = FALSE
CKA_VERIFY = FALSE
# 生命周期:会话结束后自动销毁
重要提醒:上面的配置中,会话密钥的CKA_DECRYPT被设置为FALSE。这意味着即使攻击者拿到了这个会话密钥,也只能用它加密数据,无法解密。这在某些场景下非常有用,比如日志加密——只写不读,确保日志的不可篡改性。