【问题标题】:Storing and searching for encrypted data fields like email存储和搜索加密数据字段,例如电子邮件
【发布时间】:2014-03-11 21:57:20
【问题描述】:

我想知道在数据库中存储电子邮件和电话号码等敏感字段的最佳做法是什么。假设您想通过电子邮件和电话号码进行搜索,并且该应用程序也会向其用户发送电子邮件和短信。 由于此数据是敏感数据,因此您需要对其进行加密。散列不是一种选择,因为您无法取消散列。 Rjindael 或 AES 等加密标准使数据安全,但您无法通过它搜索数据库,因为为相同输入生成的加密字符串总是不同的。

那么在这种情况下,我是否需要在表中同时存储哈希和加密字段?或者是否为这些领域部署了其他一些强大的加密技术。

【问题讨论】:

  • 如果不需要使用通配符进行搜索,例如 in (其中 email 类似 '%keyword%',那么您可以在搜索前加密搜索关键字。

标签: security encryption


【解决方案1】:

查看CipherSweet。这是一个获得许可的开源库,可在 PHP 中提供可搜索的加密。

它的实现与Ebbe's answer相似,但有更多警告:

  1. CipherSweet 自动处理密钥拆分,through a well-defined protocol
  2. CipherSweet 支持多种功能盲索引(明文转换的截断散列)以方便高级搜索。
    • 有关其设计的安全隐患的更多信息,请访问here

此外,API 相对简单:

<?php
use ParagonIE\CipherSweet\BlindIndex;
use ParagonIE\CipherSweet\CipherSweet;
use ParagonIE\CipherSweet\CompoundIndex;
use ParagonIE\CipherSweet\EncryptedRow;
use ParagonIE\CipherSweet\Transformation\LastFourDigits;

/** @var CipherSweet $engine */
// Define two fields (one text, one boolean) that will be encrypted
$encryptedRow = (new EncryptedRow($engine, 'contacts'))
    ->addTextField('ssn')
    ->addBooleanField('hivstatus');

// Add a normal Blind Index on one field:
$encryptedRow->addBlindIndex(
    'ssn',
    new BlindIndex(
        'contact_ssn_last_four',
        [new LastFourDigits()],
        32 // 32 bits = 4 bytes
    )
);

// Create/add a compound blind index on multiple fields:
$encryptedRow->addCompoundIndex(
    (
        new CompoundIndex(
            'contact_ssnlast4_hivstatus',
            ['ssn', 'hivstatus'],
            32, // 32 bits = 4 bytes
            true // fast hash
        )
    )->addTransform('ssn', new LastFourDigits())
);

实例化和配置对象后,您可以像这样插入行:

<?php
/* continuing from previous snippet... */
list($encrypted, $indexes) = $encryptedRow->prepareRowForStorage([
    'extraneous' => true,
    'ssn' => '123-45-6789',
    'hivstatus' => false
]);
$encrypted['contact_ssnlast4_hivstatus'] = $indexes['contact_ssnlast4_hivstatus'];
$dbh->insert('contacts', $encrypted);

然后从数据库中检索行就像在 SELECT 查询中使用盲索引一样简单:

<?php
/* continuing from previous snippet... */
$lookup = $encryptedRow->getBlindIndex(
    'contact_ssnlast4_hivstatus',
    ['ssn' => '123-45-6789', 'hivstatus' => true]
);
$results = $dbh->search('contacts', ['contact_ssnlast4_hivstatus' => $lookup]);
foreach ($results as $result) {
    $decrypted = $encryptedRow->decrypt($result);
}

CipherSweet 目前在 PHPNode.js 中实现,其他 Java、C#、Rust 和 Python 实现即将推出。

【讨论】:

  • Scott,这是什么原因以及如何使用来自blindIndex 的type(在较新版本中默认返回值)?这是将其存储为标签还是什么?
  • 在库的 v1 中是这样,但在 v2 中不是。
  • 嗨@ScottArciszewski 我在将数据保存到数据库时遇到问题。我在 laravel 上使用查询生成器。看不到如何创建这个盲索引以及如何在盲索引中插入数据。
【解决方案2】:

实际上,使用 AES 使用相同的密钥和相同的初始化向量 (IV) 对同一消息进行两次加密将产生相同的输出 - 始终如此。

但是,使用相同的密钥和相同的 IV 会泄露有关加密数据的信息。由于 AES 以 16 字节块加密的方式,以相同 16 字节开头并使用相同密钥和相同 IV 加密的两个电子邮件地址在开头也将具有相同的 16 字节加密消息。那些泄露这两封电子邮件以相同开头的信息的人。 IV 的目的之一就是解决这个问题。

安全搜索字段可以使用加密(具有相同密钥和相同 IV)one-way-hash 创建。单向哈希确保加密不会泄露数据。仅使用单向哈希对于例如电话号码是不够的,因为您可以轻松地暴力破解任何有效电话号码的所有单向哈希。

【讨论】:

  • 感谢您的回答.. 但一种方式哈希不是电子邮件的选项,因为需要检索该信息才能发送电子邮件。我的问题是所有这些使用 AES 加密电子邮件的应用程序,他们不通过电子邮件查询在他们的数据库上进行搜索吗?
  • 正确加密电子邮件(使用不同的 IV)并将其存储在一个字段中,然后还将如上所述的搜索字段存储在另一个字段中。
【解决方案3】:

如果您想加密您的数据,请将表放在加密文件系统上或使用为加密表提供工具的数据库。

加密数据库本身的数据会导致性能很差,原因有很多,最明显的是简单的表扫描(假设您正在通过电子邮件地址查找用户)需要解密整个记录集。

此外,您的应用程序不应该处理数据的加密/解密:如果它被泄露,那么您的所有数据也是如此。

此外,这个问题可能不应该被标记为“PHP”问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-15
    • 2011-12-15
    • 2012-11-26
    • 2011-08-18
    • 1970-01-01
    相关资源
    最近更新 更多