2、字段级加密的典型架构
做字段级加密,第一个要回答的问题是:加密逻辑放哪?
我见过不少团队一上来就选数据库内置加密,结果上线后发现查询被拖慢30%,业务方差点掀桌子。也有团队全堆在应用层,后来换了一个框架,所有加密代码都要重写,教训深刻。
说白了,加密层选错了位置,后面再优化缓存都是亡羊补牢。这一节我们把这三种典型架构掰开揉碎讲清楚。
应用程序层加密:灵活但包袱重
这是最直接的方案。你在业务代码里拿着明文,调加密库,塞进数据库。查询时再反着来一遍。
在我手上,这种架构最适合的场景:加密字段少(≤5个)、查询模式简单(只按ID查)、业务需要灵活变更加密策略。
优点也很明显:
- 加密算法随便换,今天AES-256明天SM4都行,数据库完全不知情。
- 密钥管理可以做成独立的服务,不和数据库绑定。
- 可以针对不同字段用不同密钥,甚至按用户粒度加密——我做过一个医疗项目,病历字段用患者ID+日期作为附加密钥,细粒度到每行。
但缺点……嗯,你想想看。每一处查询都可能触发解密,索引几乎作废。 更重要的是,一旦换了ORM框架或业务重构,加密代码要全量迁移。我曾经在一个旧项目里看到三个不同版本的加密实现混在代码里,有的用Java原生Cipher,有的用Hibernate拦截器,还有的直接在getter/setter里写——这简直是维护地狱。
避坑指南: 我曾经在一个高并发登录系统里用应用层加密存用户手机号。上线第一天就炸了——每次登录要解密手机号去匹配,数据库连接池直接打满。后来我们不得不在应用层前面加了一个Redis缓存明文映射,才算扛住。切记:应用层加密必须搭配写穿透缓存,否则查询性能不堪设想。
数据库层加密:省事但死板
数据库层加密又分两种:一种是全表/表空间加密(TDE),对应用完全透明;另一种是字段级加密函数,比如MySQL的AES_ENCRYPT()、PG的pgcrypto。
TDE保护的是静止数据——磁盘文件被拖走也读不了,但查询时数据库会把数据自动解密到内存,所以对应用层来说纯明文操作。但注意:它不防DBA,DBA有权限直接看内存。
字段级加密函数则更接近应用层加密——只在入库/出库时加解密,索引也是碎的。但好处是不用改业务代码,写一条SQL就能搞定。我见过一个金融项目,所有敏感字段都用MySQL的AES_ENCRYPT在存储过程里处理,后来要换成硬件加密机,改起来差点把存储过程全重写。
| 维度 | TDE(透明数据加密) | 字段级加密函数 |
|---|---|---|
| 对应用透明 | 完全透明 | 需要SQL改写 |
| 索引支持 | 索引正常 | 索引失效 |
| DBA可读 | 可读 | 不可读 |
| 加密粒度 | 表/表空间 | 字段级 |
| 密钥管理 | 数据库自带 | 手动管理 |
| 迁移成本 | 低(开关即可) | 高(需改SQL) |
我的建议: 能用TDE解决的合规需求(如等保三级要求数据加密存储)就用TDE,别整花活。真正的字段级加密需求很少需要在数据库层做——它把索引和查询复杂度的坑全踩了,收益却一般。
代理层加密:解耦但引入新隐患
代理层听起来很美:应用无感知,加密逻辑从代码里抽出来,放到一个中间件里。就像加了一个“加密网关”,SQL先过它,再转给数据库。
市面上有开源方案,比如Encryption Proxy、ShardingSphere的加密功能,也有公司自己用Netty写一个。我个人更喜欢ShardingSphere的原因就是它内置了加密字典,可以缓存常见加密结果,配合Redis能大大降低重复计算。
但代理层有个致命问题:它成了单点故障和性能瓶颈。
实际案例: 我参与的一个电商系统,峰值QPS 1.2万,用代理层做手机号加密。代理层部署了3台,正常情况延迟增加不到2ms。但有一次代理层缓存热点键失效,所有请求直接穿透到数据库,代理层CPU被打到100%,导致全站慢查。后来我们不得不做熔断——加密失败时允许明文直连,用合规代价换可用性。
代理层的优缺点我用一个表讲清楚:
| 优点 | 缺点 |
|---|---|
| 业务代码零侵入 | 增加网络跳数(1~5ms) |
| 加密策略集中管理 | 代理成为性能和故障单点 |
| 便于灰度切换 | SQL解析复杂,易出bug |
| 可复用缓存层 | 运维成本高(多一个中间件) |
| 支持多种数据库 | 故障定位困难(丢包还是加密错?) |
注意: 代理层加密最怕“透明的”——你以为无感,实际上SQL兼容性会打折扣。我见过一个项目用ShardingSphere的加密功能,结果LIKE查询加密后的密文直接报废,业务方只能改用精确匹配。所以测试阶段一定要把所有查询场景都覆盖到。
怎么选?我个人的决策框架
其实这三种架构不是互斥的。我做过几个成功的案例,都是“应用层+代理层混搭”:
- 核心敏感字段(身份证、手机号)交给代理层统一加密,业务代码不动。
- 内部标识字段(用户ID的hash值)在应用层用简单摘要算法处理,用来做索引。
- 数据库层只用TDE兜底防丢盘。
说到底,没有银弹。你选哪个架构,取决于你的合规要求、查询模式、运维能力。三者权重不同,选择就不同。下个环节我们专门讲缓存加速怎么和这些架构配合,但那是后话——先把这个框架刻在脑子里,后面的优化才有的放矢。