来源:https://www.pgedge.com/blog/why-postgres-lacks-transparent-data-encryption
为什么Postgres缺乏透明数据加密

Shaun Thomas|2026年5月22日

如果您曾经对比过数据库功能矩阵,可能会注意到一些奇怪的现象。Oracle有透明数据加密,SQL Server也有,MySQL也有,MariaDB也有。但我们都认为最好的数据库引擎——Postgres却明显缺失了。

不是没有人希望实现TDE。像PCI DSS和HIPAA这样的合规要求实际上要求数据在静态存储时加密。云部署使得“磁盘被盗”的威胁更加明显。并且在邮件列表、会议和采购部门制定的数据库评估清单中,这个问题不断被提出。那么原因是什么?

情况很复杂。真正的答案涉及近十年的邮件列表讨论、竞争性提案、关于威胁模型的根本分歧以及范围如此广泛,以至于大多数贡献者都选择退而求其次。让我们追溯历史,看看为什么这个大问题至今仍未解决。

TDE的宏伟承诺

TDE的概念很简单:数据写入磁盘时加密,读取到内存时解密。“透明”意味着加密层位于SQL引擎下方,使客户端应用程序无需特殊工具或要求即可正常运行。

TDE可以保护用户免受物理存储的盗取:被窃取或不当废弃的硬盘、掉落货车的备份磁带,或配置错误的云存储卷。TDE无法保护免受 compromised应用程序、恶意DBA、超级用户权限或SQL注入的攻击。数据库内容在服务器运行时可以被完全解密,这意味着任何可以连接和查询的人都可以读取所有数据。

这是Postgres社区多年来争论的核心问题。如果TDE只能保护磁盘盗窃,而文件系统加密(LUKS、ZFS原生加密、dm-crypt)已经能做到同样的事情,为什么Postgres要花费大量工程精力在数据库内部重新实现它呢?

根据不同来源的说法,答案包括:

  1. 合规检查框是真正的业务需求。
  2. 在数据库层管理加密确实更方便。
  3. 这样做是浪费时间,直接使用LUKS即可。

这三种观点反复出现。

寻找标准的四路努力

或许为了规避持续的争论,五家独立公司分别发明了Postgres的TDE,各自采用不同的方法。当然,其中没有一家与社区发布版本兼容,大多数都是专有软件。其中一家(Crunchy Hardened PostgreSQL)似乎已经不再存在,剩下四家。

目前只有以下选项:

  1. Percona的pg_tde是唯一的开源选项,但其全部功能(索引加密、完整WAL加密)需要Percona Server for PostgreSQL,这是他们的自定义分支。它采用两层密钥架构,数据使用AES-256-CBC,WAL使用AES-CTR,并通过HashiCorp Vault和KMIP支持外部密钥管理。临时文件仍然未加密,这对于需要写入磁盘的结果集来说是一个明显的缺陷。

  2. EnterpriseDB从版本15开始在他们的专有EDB Postgres Advanced Server中提供TDE。他们的实现可以说是最彻底的,对数据文件(AES-XTS)、WAL(AES-CTR)和临时文件(AES-CBC)进行加密。但问题是在需要他们的专有服务器的情况下,TDE必须在initdb时启用。无法在现有集群中添加加密功能。

  3. CyberTec在Postgres Enterprise Edition中包含TDE。他们的方案使用AES-CTR对整个集群进行加密,没有针对表的选择性加密选项。要么是全有,要么是全无。CyberTec一直强调他们的TDE工作影响了后续社区讨论,其原始实现可以追溯到Postgres 12时期。

  4. Fujitsu在他们的Enterprise Postgres产品中包含TDE,使用硬件加速的AES-256并符合FIPS 140-2标准。他们的方案在表空间级别进行加密,允许加密表和未加密表空间共存。这是务实的设计,但文档主要局限于白皮书和销售材料。

五家公司,四种实现,社区中没有任何Postgres版本。这说明了将此功能纳入核心的困难程度。不是缺乏动机或工程人才。这些公司每个人都做了工作,使TDE在他们的Postgres版本中成为现实。

您想防御什么威胁?

这场争论中最有教育意义的篇章始于2018年5月,NTT的Insung Moon在pgsql-hackers邮件列表中提出了一个全面的TDE设计。该提案非常雄心:表级加密粒度、两层密钥管理系统和KMS插件架构、使用独立密钥的WAL加密,以及在磁盘I/O期间的缓冲区级加密/解密。

Masahiko Sawada共同设计了这一方案。

社区的反应……很有教育意义。

Tomas Vondra直截了当地说:

“TDE过去被反复提出和讨论,每次都因为不清楚它试图解决什么问题而失败。”

这是困扰Postgres TDE提案的根本问题。在设计解决方案之前,需要达成关于所解决问题的共识。而Postgres社区从未达成这种共识。

Sawada将讨论转向威胁建模,询问TDE应该防御哪些特定攻击。答案立即分化。一些贡献者认为合规要求是足够的理由。其他人则希望保护免受好奇的DBA的侵害。还有人指出,如果威胁模型涉及恶意DBA,服务器端加密无济于事,因为DBA可以访问运行中的服务器,而服务器在查询期间会透明地解密数据。

然后Nico Williams提出了可能是整个讨论中最致命的批评。他指出,提案没有加密pg_catalog,即Postgres内部用于管理所有内容的元数据表。具有存储访问权的攻击者可以操纵目录条目以提升权限并提取TDE密钥。在他的分析中,表级加密没有保护目录保护就从根本上是不完整的:

“请注意,除非pg_catalog能够防止远程存储的操纵,否则用户表上的TDE可能可以被破坏。”

Williams进一步指出,任何DBA不是威胁的威胁模型“根本不值得在Postgres内部使用加密来应对”。文件系统加密已经处理了磁盘盗窃场景。数据库内部的加密应该保护免受数据库访问者的攻击。他指出,这个问题需要更复杂的保护机制(Merkle哈希树、MAC验证),这些会“影响性能”。

讨论分裂为竞争提案:表级 vs. 表空间级 vs. 列级加密,Crunchy Data的Joe Conway提出了透明列级转换。关于加密模式(CBC vs. XTS,Fujitsu的Tsunakawa支持NIST SP 800-38E中的XTS)的争论持续不断。密钥管理机制的争论未能解决。这些讨论在2020年1月以无进展告终。

手术的范围

使Postgres难以实现TDE的部分原因是它涉及众多子系统。Postgres TDE Wiki页面详细说明了所需工作,看起来就像《破产边缘》的副本。

Wiki确立了一个合理的核心设计理念:TDE必须安全,但也要对代码库其余部分的影响最小。由于只有一小部分用户会启用TDE,添加的代码越少,测试所需越少,TDE在Postgres发展过程中损坏的可能性也越低。

这说得有道理。现在来看看“最小影响”到底意味着什么。

缓冲区管理需要在每次写入磁盘时加密,在每次读取时解密。共享缓冲区保持明文(这就是“透明”部分),但过渡必须严密。

WAL情况则真正复杂。WAL缓冲区在内存中时为明文,但在写入磁盘时必须使用独立密钥和CTR模式加密。流式复制期间的密钥轮换也变得复杂。WAL发送者是否在传输前解密?主服务器和备用服务器能否使用不同密钥?备用服务器升级期间的密钥状态如何?

临时文件需要统一的I/O API,以便统一加密。并行查询工作线程必须共享临时密钥。由于临时文件在查询执行期间不断创建和销毁,这里的性能开销尤其明显。

Postgres生态系统中的每个备份工具都需要修改:pg_basebackup、pg_rewind、pg_waldump。只有pg_dump逃脱了,因为它通过SQL读取数据(已在共享内存中解密)。

还有许多边缘情况。 Hint-bit更新通常只翻转单个比特,在块加密下会产生完全不同的密文,因此wal_log_hints=on变得必要。CREATE DATABASE可能需要在复制的所有文件都解密和重新加密。一些GiST索引页在构建时分配了固定的LSN,导致IV重用问题。页面校验和问题(是否加密CRC)仍未解决。加密提供了弱完整性检查,但迫使所有校验和验证的命令行工具也拥有加密密钥。

Wiki列出了数十个需要加密的磁盘上文件类型,包括表数据、pg_internal.init缓存、动态共享内存段、复制槽快照、统计文件以及所有WAL段。面对这些, “最小影响” 变得不切实际。

争论与页面

最早尝试将TDE纳入Postgres核心的之一来自Ants Aasma在2016年。他提交了一个集群级加密补丁,提议使用AES-128-XTS对所有数据文件进行单一主密钥加密。设计非常简单:一个加密库GUC,一个有限的API(一个密钥设置函数,两个加密/解密函数),以及通过环境变量传递的密钥。

Robert Haas提出了最重要的技术反对意见。逐块加密WAL会破坏Postgres的撕裂页面安全性模型。如果崩溃在写入过程中撕裂加密块,就无法解密部分结果,WAL重放就会停止。这破坏了synchronous_commit保证,也就是说,它破坏了Postgres最基本的承诺之一。

Peter Eisentraut挑战了整个前提,指出文件系统级别的加密已经存在且经过测试。然后他提到工具集成负担,指出环境变量对其他进程可见,使得密钥输入不安全。

Bruce Momjian表现得非常直接:

“……我对这种用例足以作为添加该功能的理由感到不满意。”

Hans-Jurgen Schonig从CyberTec提出,需求确实存在,特别是在金融服务业,法规明确要求数据库级别加密。Stephen Frost强调备份可移植性是一个真正的优势:加密备份可以在任何有密钥的地方恢复,不同于与特定挂载点绑定的文件系统加密。

但TDE的论点从未真正战胜反对意见。Aasma似乎也意识到这一点,称TDE是“复选框功能”,公开询问社区是否真的认为值得付出努力。

早期基准测试显示2倍的原始延迟,后续性能优化被承诺但从未实现。这个讨论在2020年8月以无进展告终。补丁仍被列为“返回带反馈”。

不同的房间

在TDE讨论消失的同时,Peter Eisentraut开始研究相关但根本不同的事物。2021年12月,他提出透明列加密(TCE),这是一种客户端级功能,在数据到达服务器之前加密单个列。服务器只能看到密文。它可以存储、复制、备份,但不能读取。

Eisentraut明确指出了区别:

“此功能与平行中的磁盘加密功能无关。两者可以独立存在。”

威胁模型与TDE不同。TDE保护免受物理磁盘盗窃,而列加密保护免受DBA的攻击。服务器永远无法访问明文,因此即使是恶意管理员也无法读取受保护的列。典型用例是PCI DSS对信用卡号码、社会安全号码等敏感数据的要求。

设计聪明且复杂,需要大量核心修改:

  • 协议级别修改。
  • 用于加密插入的预编译语句,因为客户端必须拦截参数值进行加密。
  • 列加密密钥的两层密钥层级,由列主密钥包装,并通过外部KMS管理。
  • 新的DDL命令,如CREATE COLUMN ENCRYPTION KEYCREATE COLUMN MASTER KEY

注意缺少什么了吗?由于Postgres无法访问原始数据值,因此在加密列上无法在服务器上进行计算。这意味着没有索引、排序或针对加密值的WHERE子句。这相当不便。

尽管如此,该补丁在两年半中经历了数十次迭代。Jacob Champion提出了关于NULL处理、加密算法选择以及AEAD集成的重要问题。Tomas Vondra务实地建议首先发布一个基本版本,保护被动攻击者,更强的保护等待后续工作。该补丁仍被列为“返回带反馈”,因为讨论在2024年8月结束。

即使是替代的数据库层加密方法也遇到了同样的问题:完美成为敌人。

通往疯狂的方法

退一步来看这些独立讨论,一个清晰模式显现出来。Postgres的每一个TDE提案都因同样五方面的原因而失败。

没有一致的威胁模型。这是根本原因,其他一切都由此衍生。一些贡献者希望保护免受磁盘盗窃,但LUKS就足够了。一些希望保护免受DBA的攻击,但服务器端加密无法做到这一点,因为数据在内存中解密。一些希望有合规复选框,但是否值得在数据库内部进行大量工程工作呢?在达成关于TDE解决什么问题的一致意见之前,没有人能评估任何特定设计是否合适。Vondra在2018年的观察依然准确:TDE之所以失败,是因为社区无法就其目的达成一致。

范围巨大。TDE涉及缓冲区管理、WAL、临时文件、复制、每个备份工具、数十种磁盘上文件类型,以及与校验和、hint比特、索引构建和数据库创建之间的微妙交互。这不是一个简单的附加功能。正确添加TDE是一个多年的项目计划,必须在每个人都就方法达成一致之前进行。

在数据库内部进行密钥管理是一个悖论。数据库需要密钥才能运作,但将密钥存储在数据附近会破坏加密。通过SQL传递密钥暴露在查询日志中。环境变量对其他进程可见。外部KMS集成增加了部署复杂性和延迟。协议级别密钥交换需要侵入性的客户端/服务器变更。

所有方法能否解决所有问题?

核心贡献者真正持怀疑态度。Bruce Momjian的“不满意”、Tomas Vondra的“核心中无加密”立场,以及Peter Eisentraut的“文件系统加密已存在”论点,反映了拥有数十年维护Postgres的工程师们的真实看法。这些人是知道这种功能带来的维护负担的工程师,他们多次在邮件列表中看到相同提案循环而不获解决。

“使用LUKS”的论点很难被说服。正如Robert Haas所说:

“如果您只关心防止磁盘盗窃,不妨直接对整个文件系统进行加密,这可能会更性能更好。”

这在技术上是正确的,但很难向期望看到“TDE”在合规清单中的条目采购部门解释。

当然,有一个简单的初始化数据库时即加密的选项,管理密钥轮换,并默认提供加密备份。但这是否足以证明付出努力的合理性?

自最后认真尝试将TDE纳入Postgres核心以来已过去五年。Sawada的KMS讨论在2020年结束。Eisentraut的列加密讨论在2024年停滞。没有新的提案出现。对于如此需求的空白,五年时间太长了。

自助通道

目前,可以在不采用专有分支的情况下为Postgres实现磁盘加密。选项已经非常成熟,尽管有些平凡。

最常见的做法是通过LUKS(Linux Unified Key Setup)进行文件系统层加密。创建加密卷,将Postgres数据目录放在其上,即可。性能影响较小(通常具有AES-NI硬件的5-10%),密钥管理由操作系统负责,并且在数百万个部署中经过测试。

ZFS、Ceph和少数其他文件系统提供了原生文件系统加密。这些不需要额外的加密层,通常可以在表级别实现,如果需要,则支持表级粒度。这些文件系统使透明加密几乎“免费”。

AWS EBS加密、GCP Persistent Disk加密和Azure磁盘加密等云提供商的加密也可用。它们通常是透明的,通常默认启用,满足大多数合规要求。很可能Postgres云部署已经通过加密磁盘而无需特殊设置。

对于特定敏感值的列级保护,pgcrypto作为贡献扩展仍然可用。虽然它完全不像“透明”一样,但它确实将密文存储在实际列中,可以满足某些合规要求。

持续争论

Postgres是一个出色的数据库。它处理复制、分区、JSON、全文搜索、地理空间数据等一百多种复杂功能。但TDE始终未能实现。

社区的谨慎是合理的。糟糕的加密比没有加密更糟糕,因为它制造了虚假的安全感。范围巨大。威胁模型问题从未得到所有人的满意解答。虽然“使用LUKS”的论点对于采购部门来说很难被说服,但它是技术正确的。

但问题依然存在。每一年没有TDE,四个专有分支就更多依靠无法应对合规要求的客户。每个被放弃的邮件列表讨论都使得下一个提案更加困难。每个数据库评估清单中空白单元格的位置都增加了生态系统失去讨论机会的可能性。许多Postgres社区成员喜欢嘲讽MySQL,但他们自己也是如此。

也许未来的路径是没有任何人尝试过的方法:一种模块化的、基于钩子的方法,让扩展可以提供加密而不需要核心中的加密(巧妙解决了Tomas Vondra的反对意见)。也许Percona的pg_tde,尽管不完美,最终会成为事实标准。或者也许某个未来的贡献者最终提出了一个能够解决威胁模型问题的方案。

在此之前,通过查看邮件列表、关注邮件列表,并继续生活。鉴于社区对工程质量的严格要求,任何符合他们标准的解决方案都将比竞争实现更好。

当TDE最终出现时,它将像Postgres一样是最好的选择。

[ Prompt: 219.1 t/s | Generation: 11.1 t/s ]

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐