免责声明:虽然我在 ciphersweet 发布时(或至少在我意识到它时)研究了它的设计和实现,但我没有对设计进行全面的审计和安全证明,我也没有不要深入研究 PHP 的实现(很大程度上是因为我没有做太多的 PHP 工作)。不要把它误认为是审计报告(我只在我得到报酬时才做这些:P)
Ciphersweet 使用了一个漂亮而乏味的设计。斯科特在他的回答中解释了这一点,以及 Cyphersweet 的安全声明,所以我不再赘述。IMO Ciphersweet 的主要观点是,它比替代方案更安全、更难搞砸。
您提到的“重复条目泄漏”不适用于完整记录(这些记录使用标准的非确定性加密进行加密),但适用于盲索引:如果您对 HIV 状态进行索引,那么具有数据库读取权限的人可以找出哪些记录具有相同的 HIV 状态,并从那里很可能恢复所有记录的 HIV 状态。
这是盲索引的基础信息泄漏:如果您对SELECT
具有给定 HIV 状态(的函数)的所有行有足够的信息,则您有足够的信息来检查任何 2 行是否具有相同的 HIV 状态,因此更高级的密码学在那里无济于事(包括使用确定性加密,顺序保留/显示加密,......)。
好消息是,与其他设计(如显示顺序的加密)不同,键控哈希(在未知密钥下)不会透露比值是否相等更多的信息。
显然,这还不够(如 HIV 状态示例所示),因此您可以使用 3 种主要缓解措施(Ciphersweet 全部支持):
最明显的是不要在非常敏感的数据上添加盲索引:如果你不想暴露 HIV 状态数据,你为什么要创建一个索引来有效地查询它们?
使用复合索引:如果您需要索引的数据熵太低而无法安全地放入盲索引(例如 HIV 状态),您可以将其与其他一些数据一起散列(文档提供使用 SSN)例如),并支持SELECT
具有给定 HIV 状态和给定 SSN 的记录。
这是 IMO 不太有用的选项,因为您可以直接SELECT
通过 SSN(假设您对 SSN 有一个盲索引),然后检查解密记录中的 HIV 状态。将它保留在您无法在其中一个字段上拥有索引的情况下(因为它们都太低熵和/或高灵敏度)。
截断 HMAC 值,以减少信息泄漏:假设您有患者记录,均具有唯一名称,并支持按其选择 [0]。我可以通过添加具有该名称的记录(通过应用程序)来检查某个患者是否存在,然后检查数据库以查找具有相同名称哈希的第二条记录,即使应用程序本身不会授予我搜索的权限病人的名字。
使用截断散列,您可以使盲索引中的每次查找(平均)返回少量记录;说,如果你想要平均。每个查询 3 条记录,在 1 000 000 条记录中,您需要一个大小为 log2(10⁶/3) ~ 18 位的散列。这使得我描述的场景变得不可能。
我不认为 Ciphersweet 为随着数据库大小的增加而发展盲索引的大小提供了特别的支持,尽管它应该是可行的。值得庆幸的是,随着数据库的增长,不调整盲索引大小的唯一问题是轻微的性能开销:如果您的数据库变大 10 倍并且现在包含 10 000 000 条记录,则保持相同的 18 位盲索引会产生 avg。选择了 30 条记录,然后应用程序对其进行解密和过滤;解密 30 条记录以找到您感兴趣的记录应该仍然相当快。
[0] 在实际用例中,您可能会支持通过名称的规范化(小写,去除标点符号)版本进行选择;Ciphersweet 支持功能索引。
TL;DR:Ciphersweet 是安全的,可能比大多数替代方案更安全;您需要注意一些警告,这些警告存在于所有加密数据库中,以及一些操作问题,但它们都非常易于管理。