Rails 加密的列仍然允许搜索
Posted
技术标签:
【中文标题】Rails 加密的列仍然允许搜索【英文标题】:Rails Encrypted Columns that Still Allow for Searching 【发布时间】:2014-02-08 21:57:39 【问题描述】:我有一个 Rails 应用程序,它要求我加密数据库中的某些列。
根据许多示例,我已经对用户密码和电子邮件进行了加密。即使对于像我这样的菜鸟来说,这似乎也很容易。
具体的挑战是我正在为律师开发一个应用程序(实际上是一个律师),我想加密他们客户的姓名和地址,这样如果数据库被盗,该数据就无法读取。问题是最终用户(律师)将希望按客户进行搜索。
我假设根据我的要求,尽管存在争议(尽管可能缺乏知识),但数据库中的加密是正确的方法。我认为否则在应用程序中搜索将非常困难。似乎可以设置数据库,以便在启动时可以将密钥从其他地方传递到数据库中,以便密钥不在服务器上某处的文件中。
实际上,我什至不确定我正在寻找的那种加密是可能的或实用的。我已经阅读了一些内容并进行了搜索,但到目前为止,我还没有找到明确的解决方案。以下是我看过的最有希望的事情。所有这些似乎都是强大而富有创意的解决方案。请帮助我纠正任何错误印象,并指出可能有效的解决方案(如果存在)。一如既往,谢谢。
attr_encrypted
应用程序加密,但我认为实际搜索是不可能的。
pgcrypto
利用 postgresql 的数据库加密,但它不是 Rails 4.0,我似乎无法做到。不确定它是否会做我想做的事。
jmazzi/crypt_keeper
利用 postgresql 的数据库加密,但不允许对客户端数据进行搜索。
【问题讨论】:
有什么解决办法吗?我也面临同样的问题 【参考方案1】:根据attr-encrypted/README.rdoc搜索是可以的。有一个警告,它只有在所有记录都使用每个属性的相同密钥加密时才有效。
给出的例子是:
class User < ActiveRecord::Base
attr_encrypted :email, :key => 'a secret key'
attr_encrypted :password, :key => 'some other secret key'
end
# You can now lookup and login users like so:
User.find_by_email_and_password('test@example.com', 'testing')
【讨论】:
谢谢弗兰克。我正在再次查看它,但它似乎不允许搜索,除非哈希匹配。 (我认为。)排序和“喜欢”搜索似乎有问题,但也许这只是我的一个误解。 啊,是的,我没有考虑过模糊搜索或排序。似乎让排序工作的唯一方法是在检索所有记录后在 ruby 中进行。最不幸的。 所以下面的问题和答案的链接有一个可行的搜索解决方案。基本上所做的是一一解密每个列值并进行比较。这还不错,但我认为在数据库中可能会更好。我想排序问题可以通过与加密列的顺序相同的新列来解决,但这是一个糟糕的解决方法。【参考方案2】:您可以使用一种称为blind indexing 的技术。这种方法的一个优点是数据库永远不会看到密钥。
这是我创建的Ruby implementation。您可以为表达式创建索引以进行更模糊的搜索。
class User < ApplicationRecord
blind_index :initials, attribute: :name, expression: ->(v) v.split(" ").map(&:first) , ...
blind_index :phone_last4, attribute: :phone, expression: ->(v) v.last(4) ...
end
选择如何使用它,因为它会泄露某些行包含相同索引数据的事实。
这与执行LIKE
查询并非 100% 相同。为LIKE
查询建立索引的一种有效方法是trigrams。但是,如果您创建三元组并对其进行盲索引,则攻击者可以使用频率分析来破译数据。
【讨论】:
感谢安德鲁。我感谢您和提议为提供有关此主题的信息所做的所有努力。更多会很棒!就像您对频率分析的提及一样,我感到困惑。如果每个项目都加盐,频率分析会显示什么?我猜三元组必须以某种方式“揭露”数据?这是有道理的,如果不检查列中的每个项目,查询将如何工作? 如果对 trigram 使用盲索引,频率分析将显示 trigram 的频率,这可以让攻击者找出数据。以下是频率分析的工作原理:learncryptography.com/attack-vectors/frequency-analysis 谢谢,但频率部分是我理解的唯一部分。我还是不明白。如果在每个密码“123456”中添加了盐,那么它和另一个“123456”就不一样了。如果没有两个相同的元素,频率分析是如何进行的?【参考方案3】:encrypt_column gem 有一个可搜索的选项,它使用哈希进行搜索并向类添加 with_ 方法。
【讨论】:
我会看看丹,我的体重水平远远超过我的体重级别,但我不再认为解决方案真的可行,即使理论上也是如此。为了真正安全,我想我们现在知道,必须先对列进行加盐然后加密。您必须为每个值使用单独的盐。鉴于这些限制,我不明白您如何进行“模糊”搜索(SQL 中的 LIKE),更不用说直接匹配搜索了。 它不使用模糊搜索。它的作用是在数据库中存储一个哈希字段,用于基于指定盐的加密明文(以及单独的数据库列中的加密密文)。然后搜索方法获取明文,使用盐对其进行哈希处理,并使用该哈希值搜索值。 谢谢丹。所以,一个“喜欢”的 SQL 查询是行不通的。 (这就是我所说的“模糊”。)【参考方案4】:搜索crypt_keeper
gem 有什么问题?
https://github.com/jmazzi/crypt_keeper#searching
Model.search_by_plaintext(:field, 'searchstring')
# With a scope
Model.where(something: 'blah').search_by_plaintext(:field, 'searchstring')
【讨论】:
Andrey - gem README.md 的“搜索”部分涵盖了这个问题。也就是说,我认为我应该对我所说的内容和各种用例以及这一切如何运作进行一些研究,这样我才能更好地解释这个问题。以上是关于Rails 加密的列仍然允许搜索的主要内容,如果未能解决你的问题,请参考以下文章