2

我正在创建一个 CakePHP Web 应用程序。显然密码是用散列存储的,但是有没有办法安全地存储将要检索的其他字段的值?我不是在谈论像信用卡一样敏感的东西,但会存储 SSN 和薪水。我不确定存储此类信息的标准是什么,或者 CakePHP 是否有帮助程序。我使用 InnoDB 作为引擎。

4

1 回答 1

0

我不是在谈论像信用卡一样敏感的东西,但会存储 SSN 和薪水。

CakePHP 可能不直接支持这一点,但如果您使用CipherSweet,您不仅可以在存储敏感信息之前对其进行加密,还可以在 SELECT 查询中(间接)使用这些字段。

例如,您可以加密用户的 SSN 和工资,然后维护以下独立索引:

  • 用户的 SSN
  • 用户 SSN 的后 4 位
  • 用户工资

此外,Cip​​herSweet 专门使用经过身份验证的加密,并且密文是安全随机的。在幕后,它竭尽全力确保每个字段和索引都有一个唯一的 key

CipherSweet 示例

设置

<?php
use ParagonIE\CipherSweet\Backend\FIPSCrypto;
use ParagonIE\CipherSweet\BlindIndex;
use ParagonIE\CipherSweet\CipherSweet;
use ParagonIE\CipherSweet\EncryptedRow;
use ParagonIE\CipherSweet\KeyProvider\StringProvider;
use ParagonIE\CipherSweet\Transformation\LastFourDigits;

$cipher = new CipherSweet(
    new StringProvider(
        str_repeat("\xff", 32)
    ),
    new FIPSCrypto()
);

$ER = (new EncryptedRow($cipher, 'users'))
    ->addIntegerField('salary')
    ->addTextField('ssn')
    ->addBlindIndex(
        'ssn',
        new BlindIndex('ssn_idx', [], 32)
    )
    ->addBlindIndex(
        'salary',
        new BlindIndex('salary_idx', [], 16)
    )
    ->addBlindIndex(
        'ssn',
        new BlindIndex(
            'ssn_last4_idx',
            [new LastFourDigits()],
            16
        )
    )
;

加密和选择

密文是随机的,但索引是静态的。让我们加密一个用户的记录(我们称她为 Alice)。

$plaintext = [
    'username' => 'alice',
    'ssn' => '123-456-7890',
    'salary' => 135000
];
list($row, $indexes) = $ER->prepareRowForStorage($plaintext);
$decrypted = $ER->decryptRow($row);
var_dump($row, $indexes, $decrypted);

这会产生类似的东西:

array(3) {
  ["username"]=>
  string(5) "alice"
  ["ssn"]=>
  string(149) "fips:sZU-A5GvF0vrXFTuXJMoIjKrr3HAO83dSsfPXajlTkg7-ce9goff4TGsbnsmBje77USijlEp3xR0sDTo2gekZEtzoDaoNUbBcm57Va5DiFztHEV2QaREEzCdU-uV5MOg3dpxoxfq116ZRlMA"
  ["salary"]=>
  string(145) "fips:hoSB4beTtcMbOum2RoPYE8PSagvCDoeGq2mjiONm_mj6A_wobXxrMjb_x_Z-u7oMVg2TvpzXbxdN7JP0XGm6ITwefMMF5Jhq7rbYjAX38SWcCYcYyryHmBr5WgVFOJM-bvhuhAOEi6o="
}
array(3) {
  ["ssn_idx"]=>
  string(8) "3cc637b3"
  ["ssn_last4_idx"]=>
  string(4) "bb0c"
  ["salary_idx"]=>
  string(4) "5879"
}
array(3) {
  ["username"]=>
  string(5) "alice"
  ["ssn"]=>
  string(12) "123-456-7890"
  ["salary"]=>
  int(135000)
}

如果您还要将此与另一位员工的记录(我们称他为 Bob)进行比较,您会看到类似的索引:

$plaintext = [
    'username' => 'bob',
    'ssn' => '456-123-7890',
    'salary' => 135001
];

你会看到类似的东西:

array(3) {
  ["username"]=>
  string(3) "bob"
  ["ssn"]=>
  string(149) "fips:yauOEc7jF529frr7BYf16N7WNDs0koRj5yX3RhyCVPacBWPr_G8KltBSjVkNobIu2sfeWeLFCRBr1p0VHoNCADd4PPcJa6IciKjU8-K5v7Znt93g-NNlhaMzPOLqE9UVob9YxKpMb-9ZEzcW"
  ["salary"]=>
  string(145) "fips:X64DBCbralyoNuE2sZvK_HjkRhIdrnNbVY2qaHfM1s6YmMUjNnRHVS0mq_SYS3Vo982BL72RMumhtPLwa4MoewOD8ycgbLhRx74-CjyFXdqFbPkEoeLESCBu471O-19Dx-4JJVGROHM="
}
array(3) {
  ["ssn_idx"]=>
  string(8) "6950e82d"
  ["ssn_last4_idx"]=>
  string(4) "bb0c"
  ["salary_idx"]=>
  string(4) "0287"
}
array(3) {
  ["username"]=>
  string(3) "bob"
  ["ssn"]=>
  string(12) "456-123-7890"
  ["salary"]=>
  int(135001)
}

一些值得注意的细节:

  • Alicessn_last4_idx和 Bobssn_last4_idx是相同的(bb0c对于这个密钥),因为LastFourDigits应用了转换。
  • Alice 和 Bob 的 SSN 和薪水不同,因此他们的文字索引 (ssn_idxsalary_idx) 不同。

因此,如果您的选择查询如下所示:

"SELECT * FROM users WHERE ssn_last4_idx = ?"
["bb0c"]

...你会得到两行(Alice 一个,Bob 一个),因为他们的 SSN 的最后 4 位是相同的。

但是,如果您要改用它:

"SELECT * FROM users WHERE ssn_last4_idx = ? AND salary_idx = ?"
["bb0c", "0287"]

你只会得到鲍勃。相似地:

"SELECT * FROM users WHERE ssn_idx = ?"
["3cc637b3"]

...将唯一标识爱丽丝。

TL;博士

实施可搜索加密是一项艰巨的任务,但没有必要重新发明轮子。

CipherSweet 没有内置到 CakePHP 中,但没有理由不能在未来的版本中提议将其包含在内。

于 2018-09-16T04:23:20.303 回答