根据您的威胁模型,压缩和加密的结合可能会引入安全问题。如果您想在加密数据之前压缩数据,则应确保不会通过压缩率侧信道泄露信息。如果您不确定是否正在通过压缩泄露信息,**请勿在加密前压缩明文数据。**
压缩和加密结合的安全概述作为 S3 对象存储,Minio 为您提供了用于存储数据的与 S3 兼容的 API。此外,我们还尝试提供企业级数据存储系统/解决方案中预期的功能,例如安全数据加密和数据压缩。但是,有时如果您将功能结合起来,事情可能会以意想不到的方式变得非常糟糕。在这篇文章中,我将描述何时以及为何将压缩和加密结合起来不是一个好主意,在哪些情况下它可能仍然可以,以及我们为何决定不压缩加密数据。
首先,我们必须定义我们的威胁模型是什么样的,以及我们对加密的期望是什么。我们的基本模型如下所示
被动攻击者模型在此,客户端通过 SSE-C S3 API 通过 TLS/HTTPS 连接将对象上传/下载到 Minio 服务器。服务器获取客户端提供的密钥和对象,并在其存储后端存储加密后的对象。现在攻击者登场了。目前,我们假设我们的攻击者可以观察客户端和服务器之间的网络流量,以及服务器和存储后端(如果有)之间的网络流量,并且可以完全访问存储后端的对象数据。我们称此攻击者为被动攻击者,因为她不与客户端交互或影响从客户端发送到服务器的任何数据。但是,攻击者无法访问客户端或服务器的内部内存,也不知道明文对象或 SSE-C 客户端密钥。
现在我们指定我们对加密的期望。首先,只要您不知道加密密钥,您就不应该能够从加密对象中了解任何信息,除了其大小和用于加密它的算法。这意味着加密对象尤其不会泄露其明文的任何信息。其次,我们期望一个合适的加密方案能够防止攻击者在未经我们检测的情况下修改加密对象。我们通过使用现代 身份验证加密方案 来实现这一点。
在定义了我们对整个系统的假设后,我将展示两种不同类型的攻击,这些攻击利用通过压缩率侧信道泄露的信息。这两种攻击都使攻击者能够了解有关加密对象的一些信息,而这些信息在没有压缩的情况下她是无法了解的,并且违反了我们的安全假设。
检测大小相同但内容不同的对象
第一次攻击使用压缩来区分两个大小相同的对象是否包含相同的明文数据。因此,我们假设服务器使用确定性压缩算法压缩所有对象。这意味着,给定相同输入数据,压缩会再次产生相同的压缩输出——这是我所知的全部压缩算法的情况。
现在想象客户端将两个对象上传到服务器。这两个对象的大小相同——例如 5 MB。由于 TLS 的存在,观察网络流量的攻击者无法了解这两个对象的内容,但她可以通过分析流量来近似甚至确定(明文)对象的大小。然后,服务器压缩并加密对象,并将压缩和加密的数据存储在存储后端。现在有两种可能的情况
- 两个压缩和加密的对象大小相同。这意味着它们的明文数据相等,或者两个不同明文对象的压缩产生了相同大小的压缩数据。因此,我们无法对对象做出任何陈述——它们要么相等要么不同,攻击者不知道。
- 两个压缩和加密的对象大小不同。然后,攻击者立即知道这两个对象的明文不同。如果它们相等,则压缩算法会将它们压缩成相同大小的数据——因为我们知道对象明文的大小相等,并且压缩是确定性的。因此,通过反证法,对象明文必须不同。
但这已经破坏了我们的安全。攻击者能够了解一些加密对象的信息——它们是否包含相等的明文——而无需破解加密方案。因此,攻击者使用了其他信息:对象明文大小和压缩大小之间的差异。这是通过使用压缩而创建的压缩率侧信道泄露的信息。
因此,我们已经可以看到,在我们的模型中,加密前的压缩会削弱安全性。但是,有人可能会争辩说,这种攻击对现实世界场景的影响微乎其微。区分某些加密对象是否相等在大多数情况下都不会有什么区别,对吧?
好吧,到目前为止,我们只考虑了被动攻击者,他们只观察网络流量,而不与 S3 客户端或 Minio 服务器交互。但是,通过稍微更改我们的设置,我们引入了一个可以运行更强大攻击的主动攻击者。
主动攻击者模型在此设置中,S3 客户端为用户提供服务——包括可能为恶意用户的攻击者。客户端从用户那里获取一些输入,将用户的数据与客户端仅知道的一些数据(用户不知道)结合起来,并将组合后的数据作为压缩和加密的对象存储在服务器上。因此,我们更改了我们的模型,使得攻击者可以通过与 S3 客户端交互来控制对象明文的一些部分。当然,这只是一个最简单的例子。这种演示设置有很多变体,可以更贴近地反映现实世界的用例。这里重要的是,除了其监控能力外,攻击者还可以影响压缩和加密对象的一些部分。
完全/部分明文恢复
第二次攻击演示了主动攻击者如何通过利用压缩率侧信道来恢复加密对象的一些甚至全部明文。因此,攻击者的目标是了解她尚未控制的明文对象部分的一些信息。
为简单起见,让我们假设用户——也包括我们的攻击者——可以将任意数量的数据上传到 S3 客户端,该客户端将这些数据附加到其自己的 64 字节长字符串中,并将组合后的数据作为对象上传到服务器。此外,我们假设客户端的数据由相同的字节组成——例如 64 次 0xA0
。但是,我们的攻击者事先没有关于客户端数据的信息。因此,如果服务器压缩——例如使用 Snappy 算法——然后加密对象,则攻击者可以发起以下攻击来恢复整个 64 字节长的客户端字符串
- 攻击者不向 S3 客户端上传任何/空数据。这会导致客户端创建一个仅包含客户端数据的压缩和加密对象。在我们的示例中,客户端通过安全的 TLS 连接向服务器发送
64 x 0xA0
的对象有效负载。然后,服务器使用 Snappy 将该数据压缩为 6 字节长的压缩明文,并在写入存储后端之前对其进行加密。 - 通过网络流量分析,攻击者了解到对象明文长 64 字节——尽管由于 TLS 的存在,她对内容一无所知。此外,她还可以从查看加密对象中恢复,发现密文长 6 字节。现在攻击者对 Snappy 进行了一些实验,并得出结论:如果 Snappy 可以将 64 字节的字符串压缩为 6 字节,那么 64 字节的字符串必须包含 64 次相同的字节。因此,压缩已经揭示了客户端数据包含 64 次相同的字节。但是,我们的攻击者不知道是哪一个。
- 现在,攻击者再次使用 S3 客户端服务并上传 1 字节长的数据——例如
0x00
。客户端再次将其数据附加到自己的数据中,并让服务器创建另一个压缩和加密的对象。我们的攻击者将观察到对象有效负载现在长 65 字节,并且后端的对象包含 7 个加密字节。她现在可以得出结论,Snappy 无法将她的额外字节 (0x00
) 压缩到客户端的数据中——否则,对象将仅包含 6 个加密字节。她基本上重复第 3 步,同时增加她的字节(接下来她使用 0x01
,然后 0x02
,…),直到她看到一个在后端包含 6 个加密字节的对象。一旦她观察到这样的对象,她就知道了 Snappy 能够将她的字节压缩到客户端的数据中,并且她的字节等于客户端 64 字节字符串中的所有字节。
这样,攻击者在没有破解加密方案的情况下恢复了对象的全部内容,并且仅使用通过压缩率侧信道泄露的信息。当然,这种攻击之所以如此有效,是因为我做了一些简化的假设,例如客户端的数据仅包含相同的字节——特别是 0xA0
。然而,这种攻击在许多实际场景中也有效,但我们的攻击者可能需要进行更多尝试,使用更复杂的方法,并且可能只能恢复明文的一部分。例如,针对 TLS 的 CRIME 攻击是这种攻击的更高级版本,如果启用了 TLS 压缩,则可以用来窃取 HTTPS Cookie。
我们能解决这个问题吗?
为了完全消除此类攻击,我们必须禁用加密内容的压缩。更准确地说,我们必须不要在加密前压缩明文数据。在加密**之后**压缩数据是安全的,但效率也不高。安全的加密方案会产生与真正随机的比特串无法区分的密文,因此压缩无法利用数据的任何冗余来压缩它。因此,任何压缩算法都不应该能够显着压缩安全加密方案的输出。
那么压缩 + 加密完全失效了吗?
好吧,这取决于您的威胁模型。对于被动攻击者来说,如果 S3 客户端而不是 Minio 服务器压缩对象数据就足够了。然后,被动攻击者无法通过网络分析观察原始明文大小,也无法利用压缩率侧信道——因为不存在。因此,必须确保压缩率——原始数据大小和压缩数据大小之间的差异——不会泄露给攻击者。
对于主动攻击者来说,情况要复杂一些。由于她对数据在压缩和加密之前的一些控制权,即使她无法观察原始明文大小,她也可能仍然能够了解有关剩余明文的一些信息。例如,她始终可以观察她的输入如何影响整体压缩数据。通过改变她控制的数据部分,她可能能够提取有关未知部分的一些信息。因此,在主动攻击者模型中不可能完全防止压缩率攻击。但是,它们可能不够有效,无法让攻击者获得显著的优势,但这需要对特定场景进行一些分析。
Minio 将如何处理压缩和加密
我们在 Minio 尽最大努力为您提供强大的数据可用性/完整性安全保证,使用纠删码以及使用身份验证加密来保证机密性和真实性。因此,我们不会压缩任何应该在 Minio 服务器上加密的数据。压缩加密数据毫无意义,压缩明文数据会损害您的安全。因此,如果您想压缩加密对象,则必须在将其上传到服务器之前在您的 S3 客户端上进行。
我们希望这篇文章不仅对我们的用户有用,还可以帮助其他团队和项目为他们的场景找到正确的方法。当然,欢迎随时提供反馈或提出问题!