使用指南:利用jasypt-spring-boot加密解密敏感信息
1. 简介
Springboot整合Jasypt,实现配置信息的安全,如数据库连接.账号和密码.接口凭证信息等。
Jasypt可以为Springboot加密的信息很多,主要有:
-
System Property 系统变量
-
Envirnment Property 环境变量
-
Command Line argument 命令行参数
-
Application.properties 应用配置文件
-
Yaml properties 应用配置文件
-
other custom property sources 其它配置文件
2. 如何整合
以下3种方法:
-
如果你的
Spring Boot
项目使用@SpringBootApplication
或@EnableAutoConfiguration
注解,在pom中加入以下starter jar依赖。
<dependency> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency>
-
如果你不使用
@SpringBootApplication
或@EnableAutoConfiguration
两个自动配置注解的话,可以添加如下依赖:
<dependency> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-spring-boot</artifactId> <version>3.0.3</version> </dependency>
-
然后在配置Java类中使用注解
@EncryptablePropertySource
. 举例:
public class MyApplication { ... }
- 即可对整个Spring的环境的配置信息进行加密解密 (包括:System Property 系统变量、Envirnment Property 环境变量、Command Line argument 命令行参数、Application.properties 应用配置文件、Yaml properties 应用配置文件、other custom property sources 其它配置文件)
-
如果你不使用
@SpringBootApplication
或@EnableAutoConfiguration
两个自动配置注解,又不想对整个spring环境的参数进行加密解密的话,这里有第3种方法. 首先,在你的工程中添加如下依赖:
<dependency> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-spring-boot</artifactId> <version>3.0.3</version> </dependency>
-
然后,在Java配置类中添加
@EncryptablePropertySource
注解. 类似于添加spring的@PropertySource
注解. 比如:
name="EncryptedProperties", value="classpath:encrypted.properties") (public class MyApplication { ... }
-
非常方便的是,一个Java类中可以添加一个
@EncryptablePropertySources
注解,也可以添加一组@EncryptablePropertySources
注解,就像这样:
"classpath:encrypted.properties"), ("classpath:encrypted2.properties")}) ({ (public class MyApplication { ... }
另外,需要注意的是从1.8版本开始,@EncryptablePropertySource
支持YAML文件.
3. 自定义环境
从版本1.15开始,支持使用第4种方法启用加密属性. 自定义一个ConfigurableEnvironment
类,比如:EncryptableEnvironment
、StandardEncryptableEnvironment
、StandardEncryptableServletEnvironment
,与SpringApplicationBuilder
类一起使用,以这种方式自定义使用环境:
new SpringApplicationBuilder() .environment(new StandardEncryptableEnvironment()) .sources(YourApplicationClass.class).run(args);
这个方法只需要使用jasypt-spring-boot
的依赖. 不需要starter jar
依赖项. 这种方法对于在启动过程中访问加密属性非常有用. 虽然在大多数场景中不是必需的,但在定制Spring Boot
的初始化行为或整合某些初始化配置的功能时可能很有用(如日志配置)。举个具体的例子,在logback-spring.xml
文件中,我们如果要对springProperty
标签的属性启用加密,这是唯一一种方法。例如:
<springProperty name="user" source="db.user"/> <springProperty name="password" source="db.password"/> <appender name="db" class="ch.qos.logback.classic.db.DBAppender"> <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource"> <driverClass>org.postgresql.Driver</driverClass> <url>jdbc:postgresql://localhost:5432/simple</url> <user>${user}</user> <password>${password}</password> </connectionSource> </appender>
使用这种机制可以用来初始化需要传递敏感凭证的数据库日志记录Appender(Database Logging Appender)。另外,我们需要提供一个自定义的StringEncryptor
,以及一个静态构建器方法StandardEncryptableEnvironment#builder
来进行操作:
StandardEncryptableEnvironment .builder() .encryptor(new MyEncryptor()) .build()
4. 工作原理
SpringBoot启用jasypt加密解密配置机制,会做如下2件事:
-
注册一个Spring post处理器,该处理器装饰了Spring环境中包含的所有PropertySource对象,使它们具有“加密标识”,当属性按照jasypt的约定进行加密时,注册的处理器可以检测到。
-
定义了一个默认的
StringEncryptor
,可以通过常规属性、系统属性或命令行参数配置。
5. 加密的属性如何处理
使用上文中提到的整合方法1和方法2时,可以在任何包含于spring环境的配置文件中定义加密的属性。例如,使用@PropertySource注释:
name="EncryptedProperties", value = "classpath:encrypted.properties") (public class MyApplication { ... }
然后,配置文件中定义的属性使用如下标识定义:
secret.property=ENC(nrmZtkF7T0kjG/VodDvBw93Ct8EgjCA+)
现在,当你使用environment.getProperty("secret.property")
或使用@Value("${secret.property}")
时,你得到的是secret.property
的解密版本。
当使用整合方法3(@EncryptablePropertySource
)时,获取加密属性的方式是相同的,唯一的区别是,Java配置类中要使用@EncryptablePropertySource
注解。
6. 基于密码的加密配置
Jasypt 使用 StringEncryptor
类来加密属性资源. 在上文提到的3种整合方法中, 如果Spring上下文中没有自定义的 StringEncryptor
类, 则会使用Jasypt默认的类,通过在配置文件中配置如下表格中的属性来起到加密解密的作用:
配置项 | 是否必须 | 默认值 |
jasypt.encryptor.password | True | - |
jasypt.encryptor.algorithm | False | PBEWITHHMACSHA512ANDAES_256 |
jasypt.encryptor.key-obtention-iterations | False | 1000 |
jasypt.encryptor.pool-size | False | 1 |
jasypt.encryptor.provider-name | False | SunJCE |
jasypt.encryptor.provider-class-name | False | null |
jasypt.encryptor.salt-generator-classname | False | org.jasypt.salt.RandomSaltGenerator |
jasypt.encryptor.iv-generator-classname | False | org.jasypt.iv.RandomIvGenerator |
jasypt.encryptor.string-output-type | False | base64 |
jasypt.encryptor.proxy-property-sources | False | false |
jasypt.encryptor.skip-property-sources | False | empty list |
唯一必须的加密属性是加密密码,其余的配置项都可以使用默认值。虽然所有这些属性都可以在属性文件中声明,但加密器密码不应该存储在属性文件中,它应该作为系统属性、命令行参数或环境变量传递,只要它的名称是' jasypt.encryptor '。
最后一个属性,jasypt.encryptor.proxyPropertySources
用于标识jasypt -spring-boot
如何截获属性值以进行解密。默认值为false
时,使用PropertySource
、EnumerablePropertySource
和MapPropertySource
自定义的包装器实现。当为该属性指定true
时,拦截机制将在每个PropertySource
标识的属性类上实现上使用CGLib代理。在必须保留原始“PropertySource”类型的某些场景中,这可能很有用。
7. 使用自定义的加密程序
当在spring上下文中使用自定义的StringEncryptor类时,默认的加密器将被忽略,我们可以自定义相关配置,比如:
"jasyptStringEncryptor") (public StringEncryptor stringEncryptor() { PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor(); SimpleStringPBEConfig config = new SimpleStringPBEConfig(); config.setPassword("password"); config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256"); config.setKeyObtentionIterations("1000"); config.setPoolSize("1"); config.setProviderName("SunJCE"); config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator"); config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator"); config.setStringOutputType("base64"); encryptor.setConfig(config); return encryptor; }
注意,加密器的类名是一般是固定的,因为jasypt-spring-boot
从1.5
版本开始,是根据名称来检测自定义字符串加密器的。默认的类名是:
jasyptStringEncryptor
但是可以通过如下配置项来重写:
jasypt.encryptor.bean
举个例子, 如果 jasypt.encryptor.bean=encryptorBean
,那么,就可以使用encryptorBean
这个名称来定义加密器:
"encryptorBean") ( public StringEncryptor stringEncryptor() { ... }
8. 自定义Property Detector
, Prefix
, Suffix
和 Resolver
在jasypt-spring-boot-1.10
中有新的扩展,使用EncryptablePropertyResolver
来解析所有的属性:
public interface EncryptablePropertyResolver { String resolvePropertyValue(String value); }
8.1 自定义EncryptablePropertyDetector
定义一个名称为encryptablePropertyDetector
的Java类,实现并重写EncryptablePropertyDetector
接口。也可以通过配置项jasypt.encryptor.property.detector-bean
自己定义Java类的名称,而这样做后,则由定义的类来负责检测加密属性,如下例子:
private static class MyEncryptablePropertyDetector implements EncryptablePropertyDetector { public boolean isEncrypted(String value) { if (value != null) { return value.startsWith("ENC@"); } return false; } public String unwrapEncryptedValue(String value) { return value.substring("ENC@".length()); } } name = "encryptablePropertyDetector") ( public EncryptablePropertyDetector encryptablePropertyDetector() { return new MyEncryptablePropertyDetector(); }
8.2 自定义加密属性前缀和后缀
如果想为加密的属性添加不同的前缀/后缀,所有的默认实现可以继续沿用,而只是覆盖application.properties
(或 application.yml
)中的以下属性:
jasypt encryptor property prefix"ENC@[" suffix"]"