Рубрики
Без рубрики

Как шифровать и расшифровывать данные с помощью Hibernate

Узнайте, как шифровать и расшифровывать данные с помощью функций Hibernate @ColumnTransformer, которые позволяют настраивать данные столбцов при их чтении и записи.

Автор оригинала: Vlad Mihalcea.

Вступление

Сегодня один из моих подписчиков в Твиттере отправил мне следующий вопрос StackOverflow , и , отвечая на него, я понял, что он определенно заслуживает отдельного поста.

В этом посте я объясню, как вы можете шифровать и расшифровывать данные с помощью Hibernate.

Крипто-модуль PostgreSQL

Поскольку в вопросе StackOverflow упоминается PostgreSQL, нам сначала нужно включить расширение pgcrypto . Для этого нам нужно выполнить следующее утверждение:

CREATE EXTENSION pgcrypto;

pgcrypto позволит нам использовать функции pgp_sym_encrypt и pgp_sym_decrypt .

Модель предметной области

Предполагая, что у нас есть следующая сущность:

Столбец storage должен быть зашифрован при записи и расшифровке во время операции чтения.

@ColumnTransformer аннотация к спасению!

К счастью, Hibernate предлагает аннотацию @ColumnTransformer , которая была добавлена именно для такого типа сценариев.

Поэтому отображение Хранилище выглядит следующим образом:

@Entity(name = "Vault")
public class Vault {

    @Id
    private Long id;

    @ColumnTransformer(
        read = """
            pgp_sym_decrypt(
                storage,
                current_setting('encrypt.key')
            )
            """,
        write = """
            pgp_sym_encrypt(
                ?,
                current_setting('encrypt.key')
            )
            """
    )
    @Column(columnDefinition = "bytea")
    private String storage;

    //Getter and setters omitted for brevity
}

Поскольку жесткое кодирование ключа шифрования в сопоставлении не кажется очень хорошей идеей, вместо этого мы будем использовать поддержку PostgreSQL для пользовательских настроек.

Итак, ключ encrypt.key хранится в файле конфигурации postgresql.conf :

encrypt.key = 'Wow! So much security.'

Обратите внимание, что хранение ключа шифрования в файле конфигурации postgresql.conf необходимо только для того, чтобы избежать его жесткого кодирования. Это не предназначено для использования в производственной среде, где эксперт по безопасности должен посоветовать вам наилучший способ хранения этой очень конфиденциальной информации.

Время тестирования

При сохранении Хранилища сущности:

Vault user = new Vault();
user.setId(1L);
user.setStorage("my_secret_key");

entityManager.persist(user);

Hibernate будет шифровать столбец, поэтому, если вы выберете его с помощью собственного SQL-запроса:

String encryptedStorage = (String) entityManager.createNativeQuery("""
    select encode(storage, 'base64')
    from Vault
    where id = :id
    """)
.setParameter("id", 1L)
.getSingleResult();

LOGGER.info("Encoded storage: \n{}", encryptedStorage);

Вы увидите такую ценность, как эта:

Encoded storage: 
ww0EBwMC3If4VmIUn2x+0j4BKrKR9j0GFpg87Qoz/v21etflhGPE6l9p7O5Sz9yOhynbvr+gwncW

Однако при загрузке объекта в режим гибернации:

Vault vault = entityManager.find( Vault.class, 1L );
assertEquals("my_secret_key", vault.getStorage());

Атрибут storage правильно расшифровывается обратно к исходному значению.

Вывод

Как я объяснил в своей книге “Высокопроизводительная сохраняемость Java”, если вы не воспользуетесь преимуществами базового поставщика JPA или возможностями реляционной базы данных , вы потеряете множество функций, таких как простое шифрование.