如何使用加密字段搜索MySQL数据库


15

假设我需要加密某些表的字段的MySQL数据库。另外,我需要搜索一些我加密过的字段

无论如何,如何搜索这些字段?

不能一步一步地解密每个记录:假设我有成千上万的记录。解密每个记录并检查每个记录是否与搜索匹配将花费太多时间和空间。

更新2012-09-07

向数据库架构添加更多详细信息将是可以的,因为我将要实现一个新应用程序。此外,我需要扩展当前在生产环境中运行的应用程序。但是即使对于那些应用程序,也可以添加更多详细信息。

更新2012-09-08

加密是这个问题的核心。

正如一些答案所建议的那样,访问限制已经适用-但不符合加密数据的正式要求。

此正式要求不是 支付卡行业数据安全标准 [PCI]。

Answers:


11

显然,它们并不是要被查看的,因此对其进行搜索将是有问题的。

我过去使用的一个技巧是在加密数据之前对加密的数据进行哈希处理,然后将哈希存储在索引列中。当然,这仅在您搜索整个值时才有效;部分值将不会具有相同的哈希。

如果需要的话,可以通过创建“全文”哈希索引来扩展此范围,但是它可能很快变得复杂。

附录

有人建议在每次关于字典攻击易受攻击性的讨论中进行相当长时间的辩论,然后在答案中添加脚注,因此,我将讨论上述方法的潜在安全风险。

字典攻击:字典攻击是某人预先对已知值列表进行哈希处理,然后将哈希与数据库中的哈希列进行比较。如果他们可以找到匹配项,则已知值很可能实际上是正在散列的值(尽管并不确定,因为不能保证哈希值是唯一的)。通常可以通过在值后面加上或加上一个随机的“盐”来散列该值,从而避免该散列与字典匹配,但是上述答案不能使用盐,因为这样会失去可搜索性,因此可以缓解这种情况。

当处理诸如密码之类的东西时,这种攻击很危险:如果创建了流行的密码哈希字典,则可以快速在表中搜索该哈希值,并识别具有该密码的用户,并有效地提取凭证以窃取该用户的身份。

对于具有高度基数的项目(如SSN,信用卡号,GUID等),危险性较小(但与存储这些风险有不同的[风险:法律],因此我不建议您存储它们)。

这样做的原因是为了使字典攻击起作用,您需要预先构建可能值及其哈希值的字典。从理论上讲,您可以构建所有可能的SSN的字典(假设删除了所有格式排列;删除了十亿行;信用卡的数十亿个条目)...但这通常不是字典攻击的重点,并且基本上可以与蛮力攻击相提并论,在蛮力攻击中,您正在系统地调查每一个价值。

如果您想将SSN与某人匹配,还可以查找特定的 SSN或信用卡号。同样,通常不是字典攻击的重点,而是可以做到的,因此,如果这是您需要避免的风险,那么我的答案对您来说不是一个好的解决方案。

所以你有它。与所有加密数据一样,通常出于某种原因对其进行加密,因此请注意您的数据以及要保护数据的内容。


有关此答案的讨论已转移到聊天室
保罗·怀特

5

您可能想看看CryptDB。它是MySQL和PostgreSQL的前端,允许透明存储和查询加密数据。它通过在应用程序和数据库之间传递数据时对其进行加密和解密,并重写查询以对加密数据进行操作来工作。并且通过动态调整每一列的加密模式以仅公开应用程序使用的查询所需的信息。

CryptDB使用的各种加密方法包括:

  • RND是一种完全IND-CPA安全的加密方案,它不泄漏有关数据的信息(除了它的存在,对于可变长度类型,不泄漏长度),但仅允许存储和检索,不进行查询。

  • DET是RND的确定性变量,因此,两个相同的值(在同一列中)将加密为相同的密文。支持形式为的相等查询WHERE column = 'constant'

  • OPE,一种支持不等查询(例如)的顺序保留加密方案WHERE column > 'constant'

  • HOM,一种部分同态的加密方案(Paillier),允许通过将密文相乘来将加密值相加。支持SUM()查询,加法和增量。

  • SEARCH,一种支持以下形式的关键字搜索的方案WHERE column LIKE '% word %'

  • JOINOPE-JOIN,是DET和OPE的变体,可以将不同列中的值相互比较。分别支持相等和范围联接。

CryptDB的真正功能在于,它会根据看到的查询动态调整每列的加密方法,因此速度较慢和/或安全性较低的方案仅用于需要它们的列。还有其他各种有用的功能,例如将加密密钥链接到用户密码。

如果您有兴趣,建议您查看CryptDB网站上链接的论文,特别是Popa,Redfield,Zeldovich和Balakrishnan 撰写的“ CryptDB:使用加密查询处理保护机密”SOSP 2011)。这些论文还详细描述了支持不同查询类型所涉及的各种安全性和性能折衷。


1
It works by encrypting and decrypting data as it passes between the application and the database:如果正在搜索的数据已经在数据库中(已加密),则无疑会导致问题,但是很显然,搜索数据库的查询本身才传递给CryptDB(然后进行加密?)。我不明白这种方法到底有多有效?
马丁

3

我不明白为什么当前的答案尚未完全质疑要求,因此我将提出并保留为答案。

业务原因是什么?您需要加密哪些数据,为什么?如果您正在寻找PCI合规性,我可以写一篇文章。

有关您的要求的问题:

  • 结果是否需要返回存在/不存在或实际数据?
  • 您是否需要LIKE'%OMG_SEKRIT%'功能?
  • 谁看不到数据,为什么?

通常,RDBMS安全性是在用户/角色强制执行的权限基础上完成的。数据通常是由磁盘上的RDBMS加密的,而不是由列数据本身加密的,因为对于设计用于有效存储和检索数据的应用程序,这实际上没有任何意义。

受用户/角色/ API限制。在磁盘上加密。如果您要存储更重要的数据,我很想知道您为什么使用MySQL。


首先,我需要找到存在/不存在,然后找到特定记录。完全支持LIKE就可以了。但是我想知道,除了单词匹配之外,还有什么可能的。允许授权用户查看数据。该应用解密这些项目,合法用户有权查看。权限基础架构是不可选项。
SteAp 2012年

“更重要的数据”的标准是什么?
arcanine's

2

我正在调查这个问题,并遇到了您的问题。我倾向于论文“用于加密数据的搜索的实用技术”的第5.4节中概述的方法

基本要点是创建一个索引,该索引包含加密搜索文档中存在的加密关键字。技巧还在于对文档(或数据库)中存在这些关键字的位置进行加密。


1

以编程方式,一种有效的解决方案是

  1. 仅使用您的记录ID检索您要搜索的字段的所有记录
  2. 将它们解密到临时表中
  3. 针对该表执行搜索
  4. 使用ID检索与搜索条件匹配的完整记录(所有字段)
  5. 解密并返回给用户

关键是,与开始时检索和解密所有记录的所有字段相比,1和4的数据集要少得多。

希望能有所帮助。


纯文本的临时表相对(即非常)容易抓取和读取,在适当的时候中断服务器,或者只是复制temp/文件夹并爆炸,整个列的纯文本值都存在,这不是安全的操作方式
马丁

1

通过使用MYSQL的内部加密功能,使用完全搜索功能可以做到这一点。

这是一个例子:

!!! 我在这里使用MYSQL ENCODE()为简单起见,现在认为MYSQL_ENCODE是不安全的,请使用其他内部MYSQL功能之一来代替!!!

UPDATE my_table
SET field=ENCODE('my_data', 'my_password')
WHERE ID=1;

SELECT DECODE(field, 'my_password') as field FROM my_table
WHERE field LIKE 'data';

如上面的注释所建议,请勿使用ENCODE(),而应使用其他加密功能之一由于其简单性,本例中仅使用ENCODE

如果在php之类的应用程序中执行此操作,则可以在数据库网关或存储库类中执行此操作,方法是将每个表的加密列的列表/数组存储在其各自的网关类中。

class UserGateway
{
    protected $encrypted_fields = array(
        'username',
        'email'
    );

    public function get($fields, ...)
    {
        foreach ($fields as $k => $field) {
            if (in_array($field, $fields)) {
                $fields[$k] = $this->decodeSelect($field);
            }
        }

        $sql = 'SELECT '.implode(',', $fields);

        //......
    }

    protected function decodeSelect($field)
    {
        return "DECODE($field, $pass) AS $field";
    }
}

当然,这是非常粗糙和不安全的代码,未经重大改进就不能在生产中使用。但是它应该在提供总体思路上发挥其作用。


-1

假设您正在使用SQL进行搜索,并针对全部值而不是部分值(例如LIKE'value%')进行搜索...在捕获搜索数据时,请使用与加密数据时相同的算法对数据进行加密并进行搜索。

例如:

会是什么:

SELECT FieldA, FieldB 
FROM Table1 
WHERE FieldC = 'Value'

可能看起来像这样:

SELECT FieldA, FieldB 
FROM Table1 
WHERE FieldC = 'hsk&%67ghhks83'

1
不能。体面的加密将使用盐值,因此,例如,如果您对每一行都有唯一的盐,那么将需要在搜索字符串上使用盐的每一行,这将变得复杂,昂贵且非常快
马丁
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.