#php #mysql #laravel #encryption
#php #mysql #laravel #шифрование
Вопрос:
У меня есть приложение Laravel, которое использует шифрование и дешифрование с помощью функции шифрования Laravel по умолчанию.
Теперь мне нужно перенести базу данных в другую.
Я создал SQL-скрипт, который обрабатывает миграцию данных, но во время миграции мне нужно выполнить некоторые проверки в некоторых полях. Например:
insert into test.table
(valueA, valueB, valueC)
SELECT tb.a, tb.b, tc.c
from db2.tableB tb
join test.tableC tc on tb.id = tc.tb_id;
UPDATE test.table
SET valueD = CASE
WHEN valueA = 'example' THEN 1
ELSE 0
END;
Проблема в том, что некоторые из этих полей зашифрованы.
Например, ValueA будет выглядеть примерно так:
eyJpdiI6ImtTTUthN0dFT2N3Qkt6REdaamIyWGc9PSIsInZhbHVlIjoiakFIa0RFTVdCSU1LM1hWY3NUM0tVUT09IiwibWFjIjoiOGI1ZjY5ODVkYzMwYTIxMTExMzgyNjZmMTViNDllZTUzYWUxNzEyMWEwNmM5M2RmZDQzNzcwMDY4MjlkYzVlOCJ9
Я пытался использовать AES_DECRYPT(), используя APP_KEY, который у меня есть в Laravel, но скрипты всегда возвращают null. Например:
SELECT AES_DECRYPT(from_base64(valueA),'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') from
test.table;
Всегда возвращает значение NULL.
Очевидно, что ключ скрыт для целей этого сообщения.
Я думаю, что это связано с тем, что Laravel использует open_ssl при шифровании, в то время как AES_DECRYPT этого не делает. Я прав?
Есть ли способ расшифровать базу данных перед запуском моего сценария миграции или расшифровать значение в инструкции SELECT во время обновления?
Обновить:
Я настроил MySQL для использования «AES-256-CBC». Имейте в виду, что в Laravel APP_KEY выглядит примерно так: «base64: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx»
Итак, это то, что я делаю сейчас:
SET block_encryption_mode = 'aes-256-cbc';
SET @key_str = to_base64('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
SET @init_vector = (SELECT LEFT(CONVERT(encryptedVal USING binary), 16) from tableA where id =1);
SELECT encryptedVal, AES_DECRYPT(encryptedVal,@key_str,@init_vector) from tableA where id = 1;
Кстати, у меня все еще есть нулевые значения.
Любая помощь будет оценена
Комментарии:
1. Я нашел указание на то, что Laravel использует AES HMAC для целостности / аутентификации, но пока нет спецификации, как будто они не хотят, чтобы вы специально ее находили. Вероятно, он использует это .
2. Привет @MaartenBodewes. Да, он использует связанную вами черту. Основываясь на том, что вы там прочитали, знаете ли вы, как (если) я могу расшифровать непосредственно в MySQL Workbench?
3. Я немного запутался, либо это
IV CBC(plaintext)
, либо этоIV CBC(plaintext) MAC
. Если посмотретьAES_DECRYPT
, по умолчанию используется режим ECB с использованием системной переменной, и он включает IV в параметры, а не в зашифрованный текст. Как и большинство функций шифрования БД, это невероятно глупо; относительно небольшое шифрование базы данных, похоже, разработано экспертами. Но да, измените режим на CBC, извлеките IV из зашифрованного текста (первые 16 байт), а затем расшифруйте. Если это не работает, это, вероятно, из-за того, что MAC все еще присутствует.4. Еще раз спасибо за ваш ответ @MaartenBodewes. Я пытался изменить режим на CBC в MySQL с
SET block_encryption_mode = 'aes-256-cbc
помощью . Кстати, я получаю следующую ошибку:Error Code: 1193. Unknown system variable 'block_encryption_mode'
. Для меня это звучит действительно странно, потому что, если я запускаюSHOW VARIABLES LIKE "%version%";
, я получаю'version', '10.4.11-MariaDB'
, что block_encryption_mode должен присутствовать в той версии, которая у меня есть. Есть идеи, почему это происходит?5. Нет, возможно, задайте отдельный вопрос об этом после поиска.
SET block_encryption_mode = 'aes-256-cbc';
буквально, кажется, присутствует в документации. Я пытался держаться подальше от программирования БД, я больше эксперт по безопасности.
Ответ №1:
Если кому-то нужно, я закончил созданием скрипта, вызываемого из Laravel, который расшифровывает нужные мне таблицы и поля:
class DecryptDatabase extends Command
{
protected $tables = (array(
"tableA" => array(
"pk" => 'id',
"encrypted" => array('valueA', 'valueB', 'valueC'),
"name" => "tableA"
),
"users" => array(
"pk" => 'id',
"encrypted" => array('name', 'surname', 'profession'),
"name" => "users"
),
));
public function handle()
{
foreach($this->tables as $t) {
$columns = implode(',', $t['encrypted']);
$q = DB::connection('mysql2')->select('select ' . $t['pk']. ','. $columns . ' from '. $t['name']);
foreach($q as $result)
{
$pk = $t['pk'];
try {
foreach($t['encrypted'] as $enc) {
if($result->$enc != null){
$decrypted = Crypt::decrypt($result->$enc);
$query = DB::connection('mysql3')
->table($t['name'])
->where($t['pk'], $result->$pk)
->update([$enc => $decrypted]);
}
}
} catch (DecryptException $e) {
echo ("Error in decryption: ". $e);
}
}
}
echo "Decryption terminated";
return 0;
}
}
Этот скрипт расшифровывает все поля, определенные в переменной $tables.
Он использует базу данных, определенную в соединении «mysql2», в качестве источника зашифрованных значений, а затем сохраняет расшифрованные значения в базе данных, определенной в соединении «mysql3».
Первая база данных является исходной, а вторая — точной копией первой. Я сделал это для того, чтобы сохранить исходную базу данных нетронутой во время дешифрования, чтобы предотвратить повреждение данных в случае какой-либо ошибки во время дешифрования.
После расшифровки БД я могу правильно запустить свой сценарий миграции, а затем снова зашифровать БД, выполнив обратную функцию дешифрования.