Шифрование определенных столбцов в режиме гибернации: что делать с существующими данными и как правильно реализовать @ColumnTransformer?

#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
  

Решение заключается:

  1. Переименуйте существующие столбцы с помощью MySqlCommand:

     ALTER TABLE Patient CHANGE firstName firstName-old;
    
    ALTER TABLE Patient CHANGE lastName lastName-old;
      
  2. Создайте два новых столбца MySQL типа varbinary(512) с помощью команды:

     ALTER TABLE Patient ADD COLUMN lastName VARBINARY(512) NOT NULL;
    
    ALTER TABLE Patient ADD COLUMN firstName VARBINARY(512) NOT NULL;
      
  3. Обновите новые столбцы из старых с помощью следующей команды:

     UPDATE `gourvas_platform`.`Patient` SET firstName=aes_encrypt(`firstName-old`, "my secret"), lastName=aes_encrypt(`lastName-old`, "mysecret");
      
  4. Теперь мы можем безопасно удалять старые столбцы

  5. Наконец, используйте следующие аннотации 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