Статьи

Прозрачное сохранение и извлечение зашифрованных данных из базы данных

Прошло более двух месяцев с момента моего последнего поста, но июнь и июль были очень напряженными и напряженными месяцами в этом году. Сначала организация Confitura (крупнейшая бесплатная конференция для разработчиков Java в Европе) проводила все мои свободные вечера, а затем, после довольно нервного периода в больнице, родился наш второй сын. Но теперь я снова попытаюсь вести блог, поэтому, пожалуйста, следите за обновлениями.

В этой статье я кратко опишу, как мы можем хранить зашифрованные данные в нашей базе данных и извлекать их, как уже расшифровано, простым и прозрачным способом с использованием библиотеки Jasypt . В нашем случае мы будем хранить учетные данные Twitter Api, чтобы они были в безопасности в нашей базе данных, но при этом их было легко найти и использовать для публикации обновлений в нашей временной шкале.

Итак, у нас есть простая сущность, представляющая наш элемент настроек:

01
02
03
04
05
06
07
08
09
10
@Entity
public class SettingsItem implements Serializable {
 
    @Id
    @GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
    private Integer id;
 
    private String name;
    private String encryptedValue;
}

В такой таблице мы будем хранить значения для ключа потребителя Twitter, токена доступа Twitter и так далее.

Чего мы хотели бы достичь, так это того, что когда мы создаем объект SettingItem со значением в виде простого текста, а затем сохраняем его, шифрование выполняется автоматически, поэтому в БД мы зашифровали строку. И, конечно же, когда мы получаем данные из БД, мы хотим увидеть расшифрованную строку без дополнительных усилий, просто из коробки.

Джасып на помощь

jasypt-маленький

Jasypt — это простая библиотека шифрования, написанная на Java. Это освобождает разработчика от необходимости работать с деталями конфигурации низкого уровня и делает весь процесс шифрования простым и понятным. И что самое интересное сейчас, у него также есть хорошая интеграция с Hibernate, позволяющая бесшовное шифрование / дешифрование данных, хранящихся в базе данных.

Настроить

Чтобы использовать Jasypt и его модуль интеграции Hibernate, мы должны добавить два элемента в наш pom:

01
02
03
04
05
06
07
08
09
10
<dependency>
        <groupId>org.jasypt</groupId>
        <artifactId>jasypt</artifactId>
        <version>1.9.0</version>
    </dependency>
    <dependency>
        <groupId>org.jasypt</groupId>
        <artifactId>jasypt-hibernate4</artifactId>
        <version>1.9.0</version>
    </dependency>

Пользовательский тип

Затем мы должны объявить пользовательский тип Hibernate (@TypeDef) в нашей сущности:

01
02
03
04
05
06
07
08
09
10
11
12
@TypeDef(
        name="encryptedString",
        typeClass=EncryptedStringType.class,
        parameters= {
                // value will be used later to register encryptor
                @Parameter(name="encryptorRegisteredName", value="STRING_ENCRYPTOR")
        }
)
@Entity
public class SettingsItem implements Serializable {
   // (...)
}

и после этого в том же классе мы можем пометить наше поле encryptedValue для использования этого пользовательского типа:

1
2
@Type(type="encryptedString")
    private String encryptedValue;

Регистрация шифратора

Мы почти закончили. Последнее, что нам нужно сделать, это зарегистрировать шифровальщик в классе HibernatePBEEncryptorRegistry. Это можно сделать в классе инициализации нашего приложения, например, ServletContext или просто в классе с методом main (String [] args):

1
2
3
4
5
6
7
String password = System.getProperty("jasypt.password");
 
    StandardPBEStringEncryptor strongEncryptor = new StandardPBEStringEncryptor();
    strongEncryptor.setPassword(password);
    HibernatePBEEncryptorRegistry registry =
            HibernatePBEEncryptorRegistry.getInstance();
    registry.registerPBEStringEncryptor("STRING_ENCRYPTOR", strongEncryptor);

Здесь важно то, что с помощью System.getProperty () или System.getenv () мы можем безопасно настроить наш механизм шифрования, пароль предоставляется во время выполнения, устанавливая правильное значение на сервере.

Резюме

В качестве резюме, один короткий проходной тест, показывающий, что наше решение работает:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class SettingsItemRepositoryShould extends IntegrationTest {
 
    @Autowired
    private SettingsItemRepository repository;
 
    @BeforeClass
    public static void init() {
        StandardPBEStringEncryptor strongEncryptor = new StandardPBEStringEncryptor();
        strongEncryptor.setPassword("JohnDoe");
 
        HibernatePBEEncryptorRegistry registry =
                HibernatePBEEncryptorRegistry.getInstance();
        registry.registerPBEStringEncryptor("STRING_ENCRYPTOR", strongEncryptor);
    }
 
    @Test
    public void shouldEncryptAndDecryptValue() {
        // Given
        String settingName = "test";
        String value = "EncryptMe";
 
        // When
        repository.save(new SettingsItem(settingName, value));
 
        // Then
        SettingsItem settingsItem = repository.findByName(settingName);
        assertThat(settingsItem.getEncryptedValue()).isEqualTo(value);
    }
}

Ссылка: прозрачно сохраняйте и извлекайте зашифрованные данные из базы данных от нашего партнера по JCG Томаша Дзюрко в блоге Code Hard Go Pro .