【问题标题】:Full text search on encrypted data对加密数据进行全文搜索
【发布时间】:2014-04-12 18:05:35
【问题描述】:

假设我有一个存储加密文本的服务器(端到端:服务器永远不会看到纯文本)。

我希望能够对该文本进行全文搜索。
我知道这很棘手,但我的想法是使用传统的全文设计(“列表”和“匹配”表存储单词并与内容表中的 id 匹配)。当用户提交加密文本时,他们还会发送单词和相应匹配项的加盐 MD5。每个用户使用的盐都是唯一的,并且可以从他们的密码中恢复。
(简而言之:唯一的区别是“列表”表将包含散列词)

现在,这个系统会有多脆弱
请注意,我说的是“多么脆弱”而不是“多么安全”,因为我承认它不可能完全安全。
我确实了解功能(全文搜索)和安全性(从单词索引中披露一些信息)之间的权衡。例如,我了解能够获取列表和匹配表的攻击者可以获取有关原始加密文本的信息,并且可能能够通过统计分析破译某些单词(但是,由于 salt 是唯一的对于每个用户,这将需要为每个用户重复)。

这种威胁会有多严重?还会有其他严重威胁吗?

免责声明
我正在尝试构建的(并在密码学家的帮助下进行实际实施;现在我只是想了解这是否可能)是一种消费级产品,它将处理机密但不完全机密的数据.
我的目标只是提供一些足够安全的东西,这样攻击者就可以更容易地尝试窃取用户的密码(例如,侵入客户——他们最终是消费者),而不是花费大量资金尝试暴力破解索引或运行复杂的统计分析的时间和计算能力。

回复@Matthew的评论

(可能与其他回答的人有关)

  1. 如您所述,其他解决方案不可行。将所有数据存储在客户端中意味着用户无法从其他客户端访问他们的数据。服务器端加密可以工作,但我们将无法为用户提供客户端加密的额外安全性。
    唯一“真正的选择”就是不实现搜索:虽然这不是必需的功能,这对我/我们来说非常重要。

  2. 盐的保护方式与用户的解密密钥(用于解密存储文本的密钥)完全相同。因此,如果有人能够捕获盐,他或她可能也能够捕获密钥,从而产生更大的问题。
    准确地说,密钥和盐将加密存储在服务器上。它们将由客户端使用用户密码在本地解密并保存在内存中;服务器永远不会看到解密的密钥和盐。然后,用户可以更改密码,他们只需要重新加密密钥和盐,而不是所有存储的文本。据我所知,这是业内相当标准的方法。

  3. 实际上,数据库的设计如下(仅报告相关条目)。这种设计就像您在评论中提出的那样。它不允许邻近搜索(与我们不太相关)并降低频率准确度。

    • content,包含所有加密文本。列是content.idcontent.text
    • words,包含所有哈希列表。列是words.idwords.hash
    • match,匹配带有哈希/单词的文本(一对多关系)。列是match.content_idmatch.word_id
  4. 我们必须实现删除停用词等功能。当然。这不是一个大问题(当然,将在客户端完成)。最终,这些列表对国际(即非英语)用户的效用一直有限。
    我们预计查找/插入比率会非常高(即查找很多,但插入很少,而且大部分是批量)。

  5. 解密整个哈希数据库当然是可能的,但需要强力攻击。
    假设盐是安全的(根据上面的第 2 点)。如果盐足够长(你引用了 32 位......但为什么不 320? - 只是一个例子)那将需要很多时间。

总结...您证实了我对频率分析可能存在风险的怀疑。但是,我觉得这种风险并没有那么高。你能确认一下吗?
事实上,首先,每个用户的盐都是唯一的。这意味着必须同时攻击一个用户。
其次,每个文本只报告一次单词(无论它们出现多少次),频率分析变得不那么可靠。
第三……例如,对散列词的频率分析听起来不如对凯撒移位的频率分析好。仅英语就有 250,000 个单词(同样,并非所有用户都会说英语),即使某些单词比其他单词更常见,我相信无论如何也很难进行这种攻击。

PS:我们将存储的数据是消息,例如即时消息。这些很短,包含很多缩写词、俚语等。每个人都有不同的写作风格,进一步降低了频率攻击的风险(在我看来)。

【问题讨论】:

  • 你会为文本中的每个单词做一个哈希吗?盐会保密吗?为每个英文单词(少于 250000 个单词)计算一个 MD5 散列并不需要很长时间。这是我显卡上 0.1 秒的计算时间。
  • @EbbeM.Pedersen 这是一个公平的批评。 salt 将从用户的密码生成(与文本的加密密钥相同),并且对于每个用户都是唯一的。窃取盐的攻击者需要窃取密码(因此一切都失败了)或破解他/她的客户端。但是,如果您认为这还不够,我非常愿意接受建议/cmets(因为这是我提出问题的目的)。
  • @EbbeM.Pedersen 是的,它大致是文本中每个单词的一个(加盐)哈希值。例如,对于单词“dog”(加盐“blah”),客户端会将 MD5("dogblah") 作为散列词发送以存储在数据库中。 MD5 或 SHA1 或 SHA256 或类似的。
  • @72DFBF5BA0DF5BE9 我明白哈希是如何工作的。我不需要还原它们。您熟悉如何实现全文搜索引擎吗?通常,您需要两个表:“列表”和“匹配”。在“列表”中,我存储了散列而不是简单的单词。
  • 而不是漏洞,我会质疑这个系统的可用性或根本有用,在数据库中存储散列的单词有什么用?如何找回它?我认为存在设计问题,您能解释一下您要实现的目标吗?

标签: security encryption cryptography


【解决方案1】:

TL;DR:如果这需要足够安全以至于需要每个用户的端到端加密:不要这样做。

评论太长了,如果我理解正确的话,那就这样吧:

  1. 您已经对用户提交的数据进行了加密(客户端加密,所以不使用DB来处理)。
  2. 您希望用户可以搜索此内容(您对此一无所知 - 因此加密的文本块是无用的)。
  3. 您建议的解决方案是同时存储从客户端提交的散列词列表(或可能是段落)。

所以数据记录看起来像:

  • 第 1 列:加密数据块
  • 第 2 列:(空格)分隔的散列、有序、来自上述加密文本的单个单词

然后进行搜索,您只需对搜索词进行散列处理,并将散列后的词视为词来搜索第 2 列中“文本”的段落。这肯定会起作用 - 只需考虑使用无意义的搜索词搜索无意义的文本。您甚至仍然可以使用这种方法对术语进行一些邻近排名。

关注点:

  1. 与加密文本相比,将单独散列的单词作为文本的列将非常弱。您大大削弱了您的解决方案,因为不仅可以使用的单词有限,而且生成的文本容易​​受到词频分析等影响。
  2. 如果您这样做:单独存储与密码无关的盐。如果您的 salt 被捕获(仅限字典单词),则可以轻松创建彩虹表,并将其加密存储在某处。
  3. 您将失去 FTS 的许多好处,例如忽略“the”之类的词 - 如果需要,您需要自行重新实现此功能(即在提交数据/搜索词之前在客户端删除这些词)。

您暗示的其他方法不可接受/不可行:

  1. 实现搜索客户端(所有数据必须存在于客户端才能搜索)
  2. 利用数据库内置功能的集中式加密

我理解您的论点是您的方法为用户提供了对其数据的唯一访问权限(即您无法查看/解密它)。我认为这种散列方法充分削弱了数据,以至于您可以合理地计算出用户数据(也就是说,您已经降低了所需的工作量,以至于您可以在不知道用户密钥的情况下解密用户信息是非常合理的/盐)。我不会降低标准来形容这只是混淆,但你应该真正考虑一下这有多么重要。

如果您确定弱化您的系统以实现这样的搜索是有意义的,而另一种方法还不够,那么可以将文本中单词的哈希值存储为唯一出现的单词列表(即没有频率或邻近信息可用)。这会稍微减少您的实施的攻击面,但也会失去您通过将方法描述为 FTS 所暗示的好处。尽管散列词本质上成为附加到包含它们的所有记录的标签,但您可以获得这样的非常快的结果。然后搜索查找可能会变得非常快(以您的插入为代价)。

*明确一点 - 在我实施之前,我想真正确定我的业务需求需要这样的东西......

编辑:

问题的简单示例 - 假设我知道您使用的是 32 位盐,并且正在对“the”等常用词进行散列处理。 2^32 种可能的盐 = 40 亿种可能的盐(也就是说,如果您只需要对少数单词进行哈希处理以进行初始攻击,那么就不会那么多)。假设添加或前置盐,这仍然只有 80 亿个条目需要预先计算。即使是不太常见的词,您也不需要创建太多列表来确保您会获得点击(如果不是这种情况,您的数据将不值得搜索)。

然后在我们每个预先计算的盐表中查找给定文本块的最高频率盐,并使用匹配来查看它是否正确解密了文本中的其他单词。一旦你有了一个合理的候选者,就为该盐生成 250,000 字的英语彩虹表并解密文本。

我猜你可以通过访问数据库在几小时到几天内解密系统中的散列数据。

【讨论】:

  • 编辑了您将面临的问题的示例。
  • 感谢@Matthew 非常合理的回答。我有太多的 cmets,我不得不编辑我的原始帖子。请查看更新后的问题!
  • @Qualcuno 我的观点是你不需要一次攻击一个用户,你可以攻击一个(或几个)高频词并用它来计算用户的盐分。由于数据的性质(高频字典词),长盐不足以使这种攻击向量变得不合理。一旦我知道了用户的盐,我就会为每个用户生成相对较小的彩虹表。
  • 我明白你的意思。鉴于索引将排除非常常见的单词(例如“the”、“is”等),并且每个文本只会记录一次单词,我们是否可以使用其他措施来限制出现频率的机会攻击?
  • 在某些时候,您较低的“高频”词仍然会成为问题。即使不是每条记录存在的次数,您仍然可以通过引用该单词的条目数获得有关频率的一些信息。您所建议的所有事情肯定会有所帮助,但我仍然认为您不会像您想象的那样提高攻击成本……埃里克森建议的客户端搜索或索引可能是您最好的解决方案。
【解决方案2】:

首先,您拥有基于密码的密码学的所有正常漏洞,这些漏洞源于用户选择可预测的密码。在桌面计算时间不到两小时的离线攻击中,破解现实应用程序中超过 50% 的密码是很常见的。

我假设全文加密密钥是从密码派生的,或者是由密码派生密钥加密的。因此,攻击者可以根据选择的哈希索引键来测试猜测,一旦她找到密码,就可以解密所有文档。

但是,即使用户选择了高熵密码,对索引的频率分析也可能会揭示很多关于纯文本的信息。尽管在索引中丢失了词序(如果您不支持邻近搜索),您实际上是在为每个用户创建一个电子密码本。这个指数很容易受到几个世纪以来成熟的密码分析技术的影响。现代加密协议避免了 ECB,并提供“密文不可区分性”——相同的纯文本每次加密时会产生不同的密文。但这不适用于索引。

一种不那么容易受到攻击的方法是在客户端上进行索引和搜索。必要的表将捆绑为单个消息并在客户端加密,然后传输到服务器进行存储。显而易见的权衡是在每个会话中传输该捆绑包的成本。索引片段的客户端缓存可以在一定程度上降低这种成本。

最后,只有您可以权衡违规的安全成本与客户端索引的性能成本。但是索引启用的统计分析是一个重大漏洞。

【讨论】:

  • 谢谢埃里克森。请阅读我的问题附录,回复@Matthew,因为我相信它也回答了您的一些观点。关于基于密码的密码术的漏洞......你是对的,但我不能保护用户免受他们自己的愚蠢(我们将强制一些密码标准等)。最终,如果密码被盗,无论是否使用加密,数据都会受到损害。因此,我认为这与实现搜索(甚至加密)无关。
  • 那么,您再次想起频率分析的问题。我理解,但我想知道它有多严重。要破解索引,攻击者需要闯入数据库,窃取索引并希望有足够的数据来进行一些严肃的统计分析。然后呢?
  • 最后,您对整个索引进行加密并在客户端上进行搜索的想法可能很有趣。但是,这需要同时传输“表”(“单词”和“匹配”),因为仅传输“单词”仍然会使系统容易受到频率分析的影响(因为每个哈希都有一个唯一的 id)。然而,这些表可能非常大(它们可以轻松增长到 MB),并且可能需要下载太多数据(并在新插入后上传)。
  • @Qualcuno 我对您的应用程序了解得不够多,无法说明对索引的分析有多认真。这取决于信息的价值、如果被泄露会造成的损害等。但我认为你真正要质疑的是这种分析是否可行。它是,但我不认为它会非常昂贵。构建和调整工具需要一些时间,但一旦可用,就不需要太多计算来破坏每个用户的索引。从空气中提取数字,我会说 50,000 美元来打破第一个指数,每增加 1 美元。
【解决方案3】:

当您设置整个数据库加密时,MSSQL Enterprise TDE 会加密全文索引以及其他索引(自 2008 年起)。在实践中,它工作得很好,没有巨大的性能损失。无法评论如何,b/c 这是一个专有算法,但这是文档。

https://docs.microsoft.com/en-us/sql/relational-databases/security/encryption/transparent-data-encryption-tde

它不涵盖除数据库之外的任何应用程序堆栈,但您的 FTS 索引将正常工作,并且不会像在 MySQL 或 PostGres 中那样以纯文本形式存在。据我所知,MariaDB,当然还有 Oracle 也有自己的实现。 MySQL 和 PGSQL 没有。

至于密码,所有实现上的 TDE 都使用 AES 密钥,可以轮换(虽然并不总是很容易) - 因此密码漏洞落在 DBA 身上。

问题是您需要为 MSSQL TDE 的完整企业许可付费(即“标准”或“基本”云和本地版本中不可用的功能),并且您可能也为 Oracle 中的 TDE 付费。但是,如果您需要的是一个快速的解决方案并且拥有企业许可的现金(可能比开发自己的实现便宜),那么实现就在那里。

【讨论】:

    猜你喜欢
    • 2013-03-03
    • 1970-01-01
    • 1970-01-01
    • 2014-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多