I am creating a CakePHP web application. Obviously passwords are stored with a hash, but is there a way to securely store values of other fields that will be retrieved? I'm not talking anything as sensitive as credit cards, but SSN's and Salaries would be stored. I'm not sure what the standard for storing information such as this is, or if CakePHP has a helper for it. I am using InnoDB as the engine.
I'm not talking anything as sensitive as credit cards, but SSN's and Salaries would be stored.
CakePHP might not directly support this, but if you use CipherSweet , you can not only encrypt sensitive information before storing it, but still use these fields (indirectly) in your SELECT queries.
For example, you could encrypt the user's SSNs and salaries, and then maintain independent indexes of:
Additionally, CipherSweet exclusively uses authenticated encryption and ciphertexts are securely randomized . Under the hood, it goes out of its way to ensure each field and index has a unique key .
<?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
)
)
;
Ciphertexts are randomized, but indexes are static. Let's encrypt a user's records (let's call her 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);
This would produce something like:
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)
}
If you were to also compare this with another employee's records (let's call him Bob), you'd see similar indexes:
$plaintext = [
'username' => 'bob',
'ssn' => '456-123-7890',
'salary' => 135001
];
You would see something similar:
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)
}
Some details worth noting:
ssn_last4_idx
and Bob's ssn_last4_idx
were identical ( bb0c
for this key), because the LastFourDigits
transform was applied. ssn_idx
and salary_idx
) differed. So if your select query looks like this:
"SELECT * FROM users WHERE ssn_last4_idx = ?"
["bb0c"]
...you'll get two rows (one for Alice, one for Bob), since the last 4 digits of their SSNs are the same.
But if you were to do use this instead:
"SELECT * FROM users WHERE ssn_last4_idx = ? AND salary_idx = ?"
["bb0c", "0287"]
You'd only get Bob. Similarly:
"SELECT * FROM users WHERE ssn_idx = ?"
["3cc637b3"]
...would uniquely identify Alice.
Implementing searchable encryption is a nontrivial undertaking, but there's no need to reinvent the wheel.
CipherSweet isn't built into CakePHP, but there's no reason its inclusion couldn't be proposed in a future version.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.