Прошло более двух месяцев с момента моего последнего поста, но июнь и июль были очень напряженными и напряженными месяцами в этом году. Сначала организация 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 — это простая библиотека шифрования, написанная на 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); } } |