2、TDE基本原理
这一章我打算把TDE最核心的四个东西讲透:数据文件怎么加密的、日志文件为什么也要加密、内存里数据是怎么解密的、以及那个让人头疼的密钥层级关系。
说白了,TDE就是“透明”地帮你把落盘的数据糊上一层密文。你应用层根本不用改代码,数据库自己搞定。
数据文件加密:页面级透明加密
在SQL Server里,TDE加密的粒度是页面(8KB),而不是行或列。数据写到磁盘前,整页会被加密;读回内存时,自动解密。这个过程完全在数据页的I/O路径上发生,对上层逻辑透明。
具体加密流程:
- 修改后的脏页准备写回磁盘。
- 数据库引擎检查该数据页所属的数据库是否启用了TDE。
- 从内存中获取该数据库对应的数据库加密密钥(DEK)。
- 对整页(Page Header保留不加密,因为需要做校验)进行AES-256加密。
- 加密后的页面被写入数据文件。
注意:Page Header本身不加密,只加密数据行和槽位。否则数据库连这个页是谁的都搞不清楚。
日志文件加密:redo/undo日志的加密
很多人以为只加密数据文件就够了,这其实是个大坑。你想想看,事务的变更都记在日志里,如果日志文件明文,那把日志文件拷走照样能恢复出敏感数据。
日志加密的原理差不多,但有个关键区别:日志记录的加密是同步的。每一条日志写入前都要在线加密,因此对整体写负载影响更明显。不过好在日志是顺序写的,性能损失其实可控。
TDE加密的日志包括:
- 活动事务日志(Active Log)
- 已归档的日志备份文件
- tempdb的日志(如果tempdb也开启了TDE)
嗯,这里要注意:tempdb的TDE不是必选的,但我建议你开启。因为临时表、排序、索引重建都可能涉及敏感数据。
内存解密流程:从缓冲区到查询引擎
数据页从磁盘读到内存,加密状态进缓冲池?不,实际上在读入之前就解密了。流程如下:
- I/O子系统请求读取某个数据页。
- 磁盘控制器返回加密后的页面。
- 数据库引擎在放入缓冲池之前,使用DEK对该页进行解密。
- 解密后的明文页被放进缓冲池,然后才被查询引擎使用。
你可能会问:如果内存明文,那TDE还有什么用?
答案:TDE解决的是静态数据泄露风险——比如磁盘被盗、备份文件泄露、存储介质退役。它不解决运行时内存攻击。各司其职。
加密层次结构:证书、密钥、谁保护谁
这是TDE最绕的地方。我画了张图,你先看一眼。
这张图里,从上到下依次是:
- 服务主密钥(SMK):由Windows系统保护,每个实例一个。
- 数据库主密钥(DMK):由SMK加密存储,可自定义密码。
- 证书:由DMK加密,用于保护DEK。
- 数据库加密密钥(DEK):被证书加密后存储在数据库启动记录中。实际干活的就是它。
我习惯把这个层次看作“套娃保护”——每一层密钥只保护下一层的密钥,最终只有DEK碰实际数据。这样即使攻击者拿到了数据文件,没有整个链路根本解不开。
表格:四种密钥的对比
| 密钥 | 存储位置 | 作用范围 | 谁保护它 | 备份重要性 |
|---|---|---|---|---|
| SMK | 操作系统 | 整个实例 | DPAPI | 自动备份(依赖OS) |
| DMK | master 数据库 | 单个数据库 | SMK + 密码 | 强烈建议备份 |
| 证书 | master 数据库 | 单个数据库 | DMK | 必须备份私钥 |
| DEK | 数据库启动记录 | 该库所有数据页/日志 | 证书(或EKM) | 由证书间接保护 |
最后提一句:上面这些密钥的备份恢复,是TDE避坑指南里的重中之重。我曾经帮一个客户恢复数据库,结果他们丢了证书的私钥……最后只能从冷备份里翻。那场面,啧,不想经历第二次。