#java #mysql #sql #hibernate
#java #mysql #sql #режим гибернации
Вопрос:
Я создал веб-приложение с базой данных MySQL, которая хранит данные пациентов. Согласно GDPR, имена пациентов должны быть зашифрованы внутри базы данных. Для подключения и выполнения операций с БД я использую Hibernate 5.
Поискав в Интернете, я нашел много информации о том, как зашифровать определенный столбец или колонки внутри таблицы db. В основном используются следующие три подхода:
- Использование
@ColumnTransformer
аннотации Hibernate, которая наименее разрушительна для существующего кода и требует написания наименьшего количества кода - Использование Jasypt и его интеграции в режим гибернации, которая более разрушительна для существующего кода и требует нескольких строк кода.
- Реализация преобразователя атрибутов JPA, для написания которого потребовалось довольно много строк
Я решил использовать @ColumnTransformer
то, что кажется самой простой реализацией. Если вы считаете, что один из других подходов лучше, пожалуйста, скажите это, а также объясните причину.
Мой вопрос, однако, связан с существующими данными. В моей базе данных уже есть незашифрованные данные, которые должны быть зашифрованы для работы с @ColumnTransformer
реализацией. Я намерен использовать следующую аннотацию:
@ColumnTransformer(
read = "pgp_sym_decrypt(lastName, 'mySecretKey')",
write = "pgp_sym_encrypt(?, 'mySecretKey')"
)
и
@ColumnTransformer(
read = "pgp_sym_decrypt(firstName, 'mySecretKey')",
write = "pgp_sym_encrypt(?, 'mySecretKey')"
)
к соответствующим столбцам.
Как я должен зашифровать существующие данные, чтобы соответствовать приведенным выше аннотациям? Какой SQL-код я должен использовать?
Комментарии:
1. Это немного выходит за рамки, но жестко кодировать «секретный ключ» в исходном коде — очень плохая идея — это больше не секрет.
2. Я изменил его 😉
3. Ну, да, поэтому мы этого не видим (я имею в виду, что это не опубликовано в stackoverflow). Но любой, у кого есть доступ к вашему исходному коду, имеет доступ к вашим данным. И вы не можете изменить свой ключ и повторно зашифровать свои данные, когда это необходимо, без переустановки программного обеспечения. В принципе, это довольно плохие методы обеспечения безопасности, и я сомневаюсь, что какая-либо уважающая себя команда ИТ-безопасности одобрила бы это. Но опять же, я уважаю, что это потенциально выходит за рамки обсуждения, я просто хотел убедиться, что другие, читающие это, тоже знают об этом.
Ответ №1:
MySQL поддерживает следующие функции:
- AES_ENCRYPT(str, key_str);
- AES_DECRYPT(crypt_str,key_str);
Однако я не могу обновить все записи MySQL, используя следующее (потому что aes_encrypt возвращает двоичный файл):
UPDATE Patient SET firstName=AES_ENCRYPT(firstName, "mySecretKey"), lastName=AES_ENCRYPT(lastName, "mySecretKey") //NOT WORKING
Решение заключается:
-
Переименуйте существующие столбцы с помощью MySqlCommand:
ALTER TABLE Patient CHANGE firstName firstName-old; ALTER TABLE Patient CHANGE lastName lastName-old;
-
Создайте два новых столбца MySQL типа
varbinary(512)
с помощью команды:ALTER TABLE Patient ADD COLUMN lastName VARBINARY(512) NOT NULL; ALTER TABLE Patient ADD COLUMN firstName VARBINARY(512) NOT NULL;
-
Обновите новые столбцы из старых с помощью следующей команды:
UPDATE `gourvas_platform`.`Patient` SET firstName=aes_encrypt(`firstName-old`, "my secret"), lastName=aes_encrypt(`lastName-old`, "mysecret");
-
Теперь мы можем безопасно удалять старые столбцы
-
Наконец, используйте следующие аннотации Hibernate
@ColumnTransformer
:@ColumnTransformer( read = "AES_DECRYPT(lastName, 'mySecretKey')", write = "AES_ENCRYPT(?, 'mySecretKey')" )
и
@ColumnTransformer( read = "AES_DECRYPT(firstName, 'mySecretKey')", write = "AES_ENCRYPT(?, 'mySecretKey')" )
Примечание: Поскольку я использую MySQL 5.7 и функция AES_DECRYPT возвращает binary[]
вместо String
, мне нужно cast
ввести текст. Итак, вышеуказанное @ColumnTransformer
необходимо изменить на следующее:
@ColumnTransformer(
read = "cast(aes_decrypt(lastName, 'my secret') as char(255))",
write = "aes_encrypt(?, 'mysecret')"
)
и
@ColumnTransformer(
read = "cast(aes_decrypt(firstName, 'myscret') as char(255))",
write = "aes_encrypt(?, 'mysecret')"
)
Комментарии:
1. Чтобы параметры сортировки работали, вам нужно преобразовать в char даже в никогда не используемых версиях MySQL / MariaDB