存储和搜索电子邮件等加密数据字段

时间:2014-03-11 21:57:20

标签: security encryption

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

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

3 个答案:

答案 0 :(得分:4)

签出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实现即将推出。

答案 1 :(得分:2)

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

但是,使用相同的密钥和相同的IV会泄漏有关加密数据的信息。由于 AES 以16字节为单位加密的方式,两个以相同的16字节开头并使用相同的密钥和相同的IV加密的电子邮件地址在启动时也会有相同的16字节。加密的消息。那些泄露这两封电子邮件的信息的人也是如此。 IV的目的之一是反驳这一点。

可以使用加密(使用相同的密钥和相同的IV)one-way-hash创建安全搜索字段。单向散列可确保加密不会泄漏数据。仅使用单向散列对于例如电话号码是不够的,因为您可以轻松地对所有有效电话号码强制使用所有单向散列。

答案 2 :(得分:1)

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

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

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

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