如何使加密字段可搜索?

信息安全 加密 哈希 数据库 敏感数据暴露
2021-08-24 17:08:00

我正在使用attr_encrypted来存储许多字段。麻烦的是我需要能够搜索其中一些字段。

User.name

我当前的数据库有User.e_nameUser.e_name_iv. 虽然这似乎相当安全,但我无法在我的数据库中搜索“Joe Bloggs”。

散列

然后我考虑添加第三个散列字段 ( User.e_name_hash),可用于根据散列搜索词查找字段。因此,'Joe Bloggs' 搜索被散列,与所有其他散列条目相比,并找到所需的记录。但要做到这一点,我必须对该表中该字段中的所有数据都有一个恒定的盐(也是不安全的)。

僵局

了解到恒定的盐是非常不安全的,我已经没有关于如何最好地使加密字段可搜索的想法。我的选择是:

  1. 将这些字段保留为纯文本。
  2. 对这些字段进行加密并添加一个哈希字段,其中包含带有 SHA512 的恒定冗长盐(盐在每个数据库字段的所有记录中都是恒定的,但对于该字段是唯一的)。
  3. 每次需要搜索时让我的数据库解密每条记录(现在可行,但随着数量的增长效率低下)。

请注意,我需要搜索的字段不是非常敏感的——它们与医疗记录或机密信息不同。

你有什么建议?

4个回答

你已经知道答案了:3 如果你想要安全。
如果这变得太慢,您将需要一台更好的计算机,或者不止一台。就如此容易。

无论如何,请不要认为你可以决定什么数据是敏感的,因为这对于不同的人和情况有很大的不同真实故事:一个人因为吃了香草冰淇淋而损失了 20% 的年收入。你无法想象这怎么会发生?确切地说,这就是为什么:不要为其他人决定什么保密,什么不保密。.

已编辑:请参阅最后的重要说明,这是在我最初发布然后重新阅读问题后添加的。

我唯一能想到的就是使用哈希构建索引表。但是,这无疑会削弱您的安全性,因为我们正在交换完全加密,(希望)不会泄露有关哈希表内容的任何信息,这会泄露有关用户数据内容的信息(知道索引的术语数量)给定的帐户为攻击提供了频率分析的立足点)。

注意:我做出以下假设:每个用户都有不同的 iv。

在对数据库行进行加密之前,您可以读取这些行并将它们标记为将索引这些项目的表。然后,您将使用从 iv 生成的盐对令牌进行哈希处理。所以,现在,对于给定的用户,“secretfoo”在索引中保存为c9a60f248c3a99e2b7004061d5c74e5f2240426f1f0f95eaf5843aa875e68542.

搜索时,您需要遍历所有 ivs 以生成所有盐,然后执行对令牌的搜索c9a60f248c3a99e2b7004061d5c74e5f2240426f1f0f95eaf5843aa875e68542以找到包含“secretfoo”的记录。

这将是一个更快的搜索,但这里需要以速度换取安全性。因为您实际上已经为给定单词保存了一个哈希字典,所以如果要泄露数据库,则有可能(但不太可能)索引信息可用于组装原始数据。至少,它可以用来组装关于数据的元数据。话虽如此,计算起来会很困难。

让我们假设您有 100,000 个用户,每个用户大约 100 行,总表大小为 100,000,000 行数据。

解密所有 100,000,000 百万以执行非索引搜索将花费大量时间。

在上述范例下,您只需要生成 100,000 个散列并在索引中搜索每个散列一次即可找到所需的记录。此外,我们可以匹配整个字符串(散列)而不必执行任何子字符串搜索。

这具有计算 100,000 个哈希值并在 BTREE 索引表上执行 100,000 次搜索的优势,从而为我们提供了良好的结果。

正如 Mike Ounsworth 所指出的,您仍然必须决定哪些是敏感数据,哪些不是敏感数据才能进行搜索;但是,对所有令牌进行 SHA256 哈希处理比明文好几个数量级。

编辑

发表我的帖子后,我重新阅读了您的问题,并意识到您已将 iv 保存在数据库中,这会使索引容易被泄露。

解决这个问题的唯一方法是将 iv 存储在一个单独的数据库中,该数据库不暴露给网络,并且只能通过 API 访问。这是 PCI 兼容应用程序中的常见设置。

进行查询时,您的面向 Web 的应用程序必须向安全服务器询问要从中生成哈希的 iv,并执行搜索。

这是一个更复杂的实现,但如果 iv 在面向 Web 的数据库中,并且它被泄露了,那么他们所要做的就是遍历 ivs 以解密整个索引。

看看CryptDB它加密整个数据库并对加密数据运行查询,而不在数据库端解密它。您确实需要稍微更改您的应用程序以使用 CryptDB,但他们的作者声称这些只是微小的更改。它完全与语言无关。

这是描述其工作原理白皮书

一般来说,现场级别的“盲目搜索”(记录在 Medium 和其他地方)是一种强有力的、合理的姿态。对于作为数据存储样本的搜索索引:

  1. 索引:为有问题的数据运行适当的字段分析器(例如,雪球分析器等 - 例如删除元音和重复字母的名称)。

  2. 散列分析器的结果(慢散列提高安全性)。一个。使用与记录关联的随机盐 - 加密盐。 https://stackoverflow.com/questions/18142745/how-do-i-generate-a-salt-in-java-for-salted-hash

  3. 将哈希作为十六进制作为字符串存储在索引中(哈希是单向的)。

  4. 加密字段数据和/或将其分组并为其分配“密码参考ID”。Cipher-Reference-ID 将有一些其他表,其中包含密钥 ref(非机密)、alg 等(想想 JWE 类型标准元数据)。

  5. 将 Cipher-Reference-ID 存储到与字段相同的索引文档中。

流程现在为:

"Will Smith" becomes "WL SMTH" by Analyzer.
"WL SMTH" becomes "FF0XAD00" after hashing.
Cipher-Reference-ID "5" is created.
Document (non-sensitive data or just a ref) stored with fields:
  Name (String): FF0XAD00
  Cipher-Reference-ID (int): 5

-- 现在搜索:

系统从某个安全源将所有盐加载到内存中。

a. User types "Wil Smith" (misspelled to demonstrate fuzzy search).
b. Analyzer resolves to "WL SMTH".
c. Hash to "FF0XAD00" using salt.
d. Search with 'token' type parser matches Document on Name=FF0XAD00
e. Results from search-engine then go through challenge:
    Get secret-key from user to determine access (do this in advance)
    Look-up Cipher-Reference-ID=5 to find all of the JWE type things.
    Decrypt with secret-key and cipher-meta info.
    Display search result: "Name=Will Smith"

静止时只有散列和密码引用(没有数据,没有密钥)。

可以说,对整个数据集的彩虹攻击是不可能的,因为哈希是加盐的,而且盐存储库是独立且安全的(不能在静止时访问)。唯一严重的缺点是性能(索引速度和较小程度的搜索)。搜索需要散列、搜索匹配(快速)和解密。例如,如果将所有“敏感”字段组合成一个密码块,然后在渲染过程中稍后解析出来,则后者可以更快。这样一来,如果说有十个加密字段,就只有一次解密操作。