自从我在这里发表上一个帖子以来已经有两个多月了,但是今年六月和七月非常忙碌而密集。 首先, Confitura的组织(欧洲最大的Java开发人员免费会议)参加了我所有的免费晚会,然后在相当紧张的住院期间,我们的第二个儿子出生了。 但是,现在,我将尝试再次定期写博客,请继续关注。
在本文中,我将简要介绍如何使用Jasypt库以一种简单,透明的方式将加密的数据存储在数据库中并检索已解密的数据。 我们的用例将是存储Twitter Api凭据,以便它们在我们的数据库中是安全的,但仍易于检索并用于在我们的时间轴中发布更新。
因此,我们有一个简单的实体来代表我们的设置项:
@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对象,然后对其进行持久化时,将自动执行加密,因此在数据库中我们已对String进行了加密。 当然,当我们从数据库中检索数据时,我们希望开箱即用地看到解密的String,而无需付出额外的努力。
Jasypt进行救援
Jasypt是一个用Java编写的简单加密库。 它使开发人员免于处理低级配置细节,并使整个加密过程变得简单而直接。 而且现在最有趣的是,它还与Hibernate很好地集成在一起,可以对存储在数据库中的数据进行无缝加密/解密。
设定
要使用Jasypt及其Hibernate集成模块,我们必须在pom中添加以下两项:
<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):
@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 {
// (...)
}
然后在同一个类中,我们可以标记我们的ActivatedValue字段以使用此自定义类型:
@Type(type="encryptedString")
private String encryptedValue;
注册加密器
我们快完成了。 我们要做的最后一件事是在HibernatePBEEncryptorRegistry类中注册加密器。 这可以在我们的应用程序的初始化类(例如ServletContext)中完成,也可以仅在具有main(String [] args)方法的类中完成:
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(),我们可以安全地配置我们的加密机制,通过在服务器计算机上设置适当的值在运行时提供密码。
摘要
作为总结,一个简短的通过测试表明我们的解决方案有效:
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);
}
}