列级加密基本原理:加密算法、密钥管理、数据模型
说实话,列级加密听起来挺唬人的。很多新手一听“加密”两个字,就觉得是密码学大牛才该碰的东西。
但你想一想,我们真正要解决的场景其实很简单:表里有一列敏感数据,比如身份证号、手机号、银行卡号,我不想让DBA直接select *就能看到明文。怎么办?
把这一列单独拎出来,加密存储。这就是列级加密的初心。
加密算法:对称与非对称,怎么选?
我做过的几个项目中,90%的列级加密场景用的都是对称加密。原因很简单——性能。
你想想看,数据库里一查可能就是几十万行,每行都要解密。如果都用非对称,CPU直接报警。
| 对比维度 | 对称加密(如AES) | 非对称加密(如RSA) |
|---|---|---|
| 加解密速度 | 快,硬件加速支持好 | 慢,不适合批量操作 |
| 密钥数量 | 加解密同一把密钥 | 公钥/私钥分离 |
| 密钥分发难度 | 需要安全通道传递密钥 | 公钥可以公开分发 |
| 适用场景 | 数据量大、列级加密首选 | 密钥交换、数字签名 |
我个人习惯,线上列级加密基本都是AES-256-GCM。为什么是GCM?因为AEAD,自带认证标签,能防篡改。
我曾经遇到过一个坑:早期项目用的是AES-256-CBC,结果有一天发现数据被人篡改了一部分,但解密程序没报错。嗯,CBC不提供完整性校验。从那以后,我再也没用过CBC。
密钥管理:难点不是加密算法,是密钥
这话你可能听过很多次了。但我还是要再说一遍:加密系统的安全性,取决于密钥管理,不是算法。
一个简单的例子:你把AES密钥硬编码在应用配置里,那加密形同虚设。我在项目里见过好几次这种“僵尸加密”。
密钥的生命周期
- 密钥生成:使用安全的随机数生成器,不要用Math.random()这类伪随机。
- 密钥存储:建议使用硬件安全模块(HSM)或密钥管理服务(KMS)。
- 密钥分发:只有授权应用才能获取密钥,DBA甚至不应该知道密钥存在。
- 密钥轮换:定期更换,旧密钥保留用于解密历史数据。
- 密钥销毁:彻底清除,不留痕迹。
说到密钥轮换,很多人问我:“旧数据怎么办?”
这就是信封加密的用武之地。主密钥(KEK)只用来加密数据密钥(DEK),数据密钥才用来加密实际列。轮换时只换主密钥,数据密钥不变,不用重新加密整个表。
数据模型:表结构怎么改?
这是落地时最实际的问题。你不可能为了一个加密列,把整个表推倒重来。
我归纳了三种常见的数据模型方案:
| 方案名称 | 实现方式 | 适用场景 |
|---|---|---|
| 明文+密文双列 | 新增encrypted_column,存原始列加密后的值 | 逐步迁移,向下兼容 |
| 密文替代原文 | 直接修改原列类型为varbinary,存密文 | 全新系统,不兼容老数据 |
| 应用层加密+透明解密 | 应用层加解密,数据库只存密文 | 已有系统,最小化改造成本 |
我个人推荐明文+密文双列方案。虽然多占一列空间,但胜在安全。你可以先写双写,等确认密文数据都正确后再切过去。
-- 示例:双列表结构
CREATE TABLE users (
id INT PRIMARY KEY,
id_card_plain VARCHAR(18), -- 明文,后续删除
id_card_enc VARBINARY(256), -- AES-256-GCM 密文
created_at TIMESTAMP DEFAULT NOW()
);
知识体系总览
下面这张图把今天我讲的三块内容串起来了。你可以把它当作本章的“脑图”。
你看,结构其实不复杂。加密算法是“刀刃”,密钥管理是“刀柄”,数据模型是“刀鞘”。三者配合,才能安全落地。