列级加密基本原理:加密算法、密钥管理、数据模型

说实话,列级加密听起来挺唬人的。很多新手一听“加密”两个字,就觉得是密码学大牛才该碰的东西。

但你想一想,我们真正要解决的场景其实很简单:表里有一列敏感数据,比如身份证号、手机号、银行卡号,我不想让DBA直接select *就能看到明文。怎么办?

把这一列单独拎出来,加密存储。这就是列级加密的初心。

加密算法:对称与非对称,怎么选?

我做过的几个项目中,90%的列级加密场景用的都是对称加密。原因很简单——性能。

你想想看,数据库里一查可能就是几十万行,每行都要解密。如果都用非对称,CPU直接报警。

对比维度 对称加密(如AES) 非对称加密(如RSA)
加解密速度 快,硬件加速支持好 慢,不适合批量操作
密钥数量 加解密同一把密钥 公钥/私钥分离
密钥分发难度 需要安全通道传递密钥 公钥可以公开分发
适用场景 数据量大、列级加密首选 密钥交换、数字签名

我个人习惯,线上列级加密基本都是AES-256-GCM。为什么是GCM?因为AEAD,自带认证标签,能防篡改。

我曾经遇到过一个坑:早期项目用的是AES-256-CBC,结果有一天发现数据被人篡改了一部分,但解密程序没报错。嗯,CBC不提供完整性校验。从那以后,我再也没用过CBC。

我的建议:列级加密首选AES-256-GCM,密钥长度256位,IV随机生成,附加认证数据(AAD)可以带上行ID或表名,进一步提升安全性。

密钥管理:难点不是加密算法,是密钥

这话你可能听过很多次了。但我还是要再说一遍:加密系统的安全性,取决于密钥管理,不是算法。

一个简单的例子:你把AES密钥硬编码在应用配置里,那加密形同虚设。我在项目里见过好几次这种“僵尸加密”。

密钥的生命周期

  1. 密钥生成:使用安全的随机数生成器,不要用Math.random()这类伪随机。
  2. 密钥存储:建议使用硬件安全模块(HSM)或密钥管理服务(KMS)。
  3. 密钥分发:只有授权应用才能获取密钥,DBA甚至不应该知道密钥存在。
  4. 密钥轮换:定期更换,旧密钥保留用于解密历史数据。
  5. 密钥销毁:彻底清除,不留痕迹。

说到密钥轮换,很多人问我:“旧数据怎么办?”

这就是信封加密的用武之地。主密钥(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()
);
注意:明文列不要长期保留。数据验证通过后,尽快清空明文列,或者用触发器阻止直接select明文列。

知识体系总览

下面这张图把今天我讲的三块内容串起来了。你可以把它当作本章的“脑图”。

列级加密核心知识体系 列级加密 加密算法 密钥管理 数据模型 AES-256-GCM RSA/ECC 信封加密 HSM/KMS 双列方案 密文替代 核心设计理念:加密不可逆 + 最小密钥暴露 应用层持有密钥,数据库只存密文,DBA无法直接读取敏感字段。

你看,结构其实不复杂。加密算法是“刀刃”,密钥管理是“刀柄”,数据模型是“刀鞘”。三者配合,才能安全落地。

一句话总结这一章:选对算法(AES-256-GCM),管好密钥(信封加密+HSM/KMS),设计好表结构(双列方案优先)。这三件事搞定,列级加密的核心就握在手里了。