密钥管理基础:对称密钥、非对称密钥、哈希算法、密钥生命周期

谈到密钥权限接口设计,有一件事必须先搞清楚——密钥本身到底是怎么一回事。我见过不少团队,RBAC 模型画得漂漂亮亮,结果密钥管理一塌糊涂,最后接口全被攻破。说白了,密钥是权限的“门锁”,锁不好,RBAC 再牛也没用。

这一章我们就把基础打牢。我会从对称密钥、非对称密钥、哈希算法讲起,再串一个密钥生命周期出来。嗯,这都是我日常工作天天打交道的东西。

3.1 对称密钥:又快又简单,但有个致命短板

对称密钥,就是加密和解密用同一把密钥。你拿它加密文件,对方用同一把解密,像一把钥匙开一把锁。最常用的算法是 AES(Advanced Encryption Standard)。

对称密钥的特点: 加密速度快,适合大量数据。但密钥分发是个大麻烦——怎么安全地把密钥交给对方?

我在项目中遇到过,一个老系统用 DES 做对称加密,密钥硬编码在配置文件里。结果运维小哥把配置文件传到公开 Git 仓库了……那一周我都在改密钥。所以后来我坚定地要求:对称密钥必须通过密钥管理系统(KMS)生成和分发,代码里绝不能出现明文密钥。

// 伪代码示例:使用 AES-256 加密
byte[] key = generateRandomKey(32); // 256 位
byte[] iv = generateRandomIV(16);   // 初始向量
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
byte[] cipherText = cipher.doFinal(plainText);

3.2 非对称密钥:公钥随便给,私钥打死也不能丢

非对称密钥是一对儿——公钥(公开)和私钥(保密)。公钥加密的数据只有私钥能解,反之亦然。RSA 和 ECC(椭圆曲线)是主流。RSA 经典但慢,ECC 同等安全强度下密钥更短、性能更好。

我建议:接口签名优先用 ECC,加密少量数据(比如传输对称密钥)用 RSA。别问为什么,问就是项目经验——你用 RSA 签几万条数据试试?

避坑指南: 我曾经见过有人把私钥直接放在客户端的代码里做签名,美其名曰“离线验证”。结果用户反编译 Apk,私钥泄露,整个系统被伪造请求淹没。记住:私钥永远只在服务器端,客户端只能有公钥。

3.3 哈希算法:单向的指纹,不是加密

哈希算法把任意长度的数据变成固定长度的摘要,不可逆。SHA-256 现在最常用。很多人搞混哈希和加密,以为哈希是“加密”……其实哈希是单向的,你不能把摘要变回原文。它适合做完整性校验、密码存储(加盐后)、防篡改。

举个例子,你下载一个安装包,网站提供 SHA-256 哈希值。你用工具算一下本地文件的哈希,对比一致,就说明没被修改过。这就是哈希的典型用途。

// 计算 SHA-256 哈希
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(data); // 32 字节

选择哈希算法的建议: 务必用 SHA-2 系列(SHA-256/384/512),别再碰 MD5 和 SHA-1。我自己的项目里,即使只是内部校验,也只用 SHA-256。防小人防不住,但贪图省事用弱算法?那就是给自己挖坑。

3.4 密钥生命周期:从出生到销毁,一个环节都不能漏

密钥不是永久的。它像人一样有生命周期:生成、分发、使用、轮换、撤销、销毁。每个阶段都有安全要求。下面这个表格是我自己整理的检查清单,每次设计接口时我都会对着过一遍。

阶段 关键动作 常见错误
生成 使用真随机数生成器(如 /dev/urandom、KMS) 用伪随机或固定种子
分发 通过安全通道(TLS、KMS API)传递 明文传输、硬编码
使用 限制使用范围(IP、时间、次数) 无限制使用、日志泄露密钥
轮换 按策略定期更换(如 90 天、或有事件触发) 从来不换,或者一次性全量更换导致服务中断
撤销 标记为不可用,保存撤销记录 只删不记,事后审计找不到原因
销毁 物理清零或覆盖,清除所有备份 只软删除,残留数据被恢复

我习惯在每个 RBAC 接口设计之初就规划好密钥版本和轮换策略。说白了,密钥轮换就像换锁——你不能等旧锁被撬了才想起来换。我曾经因为没及时轮换,导致某次攻击者拿到了半年内的所有历史数据。嗯,那种教训一次就够了。

3.5 把这些串起来:密钥生命周期全景

下面这张图是我自己画的,把密钥从出生到死亡的全流程串了起来。你看一遍就能明白密钥管理的核心脉络。

密钥生命周期流程 生成 分发 使用 轮换 撤销 销毁 按策略循环 撤销后启动新密钥生成 虚线表示可选/异步流程,实线为必经步骤。轮换后旧密钥通常进入撤销状态。

实用技巧: 在 RBAC 接口设计中,每次请求携带的密钥版本号可以帮你快速定位该密钥处于哪个生命周期阶段。我一般在 JWT 的 payload 里额外加一个 kid(Key ID)字段,配合 KMS 查询密钥状态,做有效性校验。

搞清楚了这三种密钥形态和生命周期,你就能更好地理解后面的“密钥权限接口”为什么要有那些约束——比如为什么需要密钥版本、为什么签名密钥要定期轮换、为什么撤销后旧密钥不能立即删除而要留一段时间。这些都不是拍脑袋定的,而是密钥管理本身的规律。