这里首先需要说明的就是为什么要进行配置文件加密。在当今这个移动互联网横行的时代里,无论是企业的隐私还是个人的隐私都是需要得到保护的。所以我们在实际的操作中会采用各种各样的方式来确保个人隐私不被泄露。
而对于我们的Spring Boot开发的应用也是一样的,它是通过一个Jar包就可以运行的,但是在运行过程中不难保证这个Jar包泄露,然后破坏者利用jar包中的配置文件配置的数据库密码等内容登陆数据库,最终导致信息泄露等问题,那么我们应该如何做才能保证不会出现这些问题呢?下面我们就来看一下Spring Boot的配置文件是如何实现数据库连接信息脱敏处理的。
配置文件如何脱敏处理?
在我们的Spring Boot配置文件中会有大量的敏感信息存在,例如数据库的连接地址,数据库账号密码等等信息,这些信息一旦泄露,造成的损失也是巨大的,那么我们如何去实现这些信息的加密处理呢?
一般的思路都是,在编写的时候我们进行加密,然后在实际使用的时候进行解密使用,这样的话这个加解密的工作都是在动态的过程中完成的,所以就不会出现问题。但是这样的新的问题就出现了,我们每次都需要完成这个动态的操作,一次两次还可以,但是如果重复次数过多的话就会带来各种问题?而下面我们提供的这种方案就是通过场景启动器来解决,让使用者可以在毫无感知的情况下完成上面的动态操作。
实践操作
第一步、需要在POM文件中引入场景启动器的依赖项。
com.Github.ulisesbocchiojasypt-spring-boot-starter3.0.3
第二步、既然是需要完成加密操作,那么我们就需要在配置文件中添加对应的密钥,然后在进行解密的时候使用对应的密钥进行解密操作。
jasypt:encryptor:password: YYJDkj12kwq1r322r2rjk
第三步、实现数据加密操作,这里我们编写一个Controller的控制来进行操作,当然我们还可以通过编写测试的方式进行数据加密操作
@RestControllerpublic class JasyptController {@Autowiredprivate StringEncryptor stringEncryptor;@GetMApping("/hello")public String hello(){String url =stringEncryptor.encrypt("jdbc:MySQL://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8");String name = stringEncryptor.encrypt("root");String password = stringEncryptor.encrypt("root");System.out.println("数据库连接 " + url);System.out.println("用户名 " + name);System.out.println("密码 "+ password);return "OK";
运行结果如下。
我们会看到数据库的连接地址、用户名、密码都进行了加密,这个时候我们就可以将加密后的内容添加到配置文件中。
注意,这里我们需要进行一个简单的分析,每个场景启动器都有自己对应的自动配置文件,这个加密的场景启动器也不例外。我们先来找到他对应的自动配置类JasyptSpringBootAutoConfiguration
JasyptSpringBootAutoConfiguration@Configuration@Import(EnableEncryptablePropertiesConfiguration.class)public class JasyptSpringBootAutoConfiguration {
会看到其源码非常简单,一般来说,在我们的自动配置类中都会有配置项有关的内容,但是在这个配置类中却没有。但是却引入了EnableEncryptablePropertiesConfiguration一个外部的配置类。那么这个类到底是什么?
@Configuration@Import({EncryptablePropertyResolverConfiguration.class, CachingConfiguration.class})public class EnableEncryptablePropertiesConfiguration {private static final Logger log = LoggerFactory.getLogger(EnableEncryptablePropertiesConfiguration.class);public EnableEncryptablePropertiesConfiguration() {@Beanpublic static EnableEncryptablePropertiesBeanFactoryPostProcessor enableEncryptablePropertySourcesPostProcessor(ConfigurableEnvironment environment, EncryptablePropertySourceConverter converter) {return new EnableEncryptablePropertiesBeanFactoryPostProcessor(environment, converter);
在这个配置文件中我们需要注意的有两个地方,一个是EncryptablePropertyResolverConfiguration 配置类,另一个则是EnableEncryptablePropertiesBeanFactoryPostProcessor的前置处理器。对于前置处理器,有兴趣的读者可以查询一下。这里我们不做过多说明直接分析源码即可。
在EncryptablePropertyResolverConfiguration源码中为我们定义了很多的加解密的Bean对象。我们可以根据具体的需求来使用具体的加解密的对象,当然我们也可以自定义自己的加解密方法对象,这个需要参考GitHub上的相关文档。这里先不做过多说明。
EnableEncryptablePropertiesBeanFactoryPostProcessor 前置处理器则是加载一些与配置环境相关的内容。也就是说需要使用Jasypt就必须要加载一些与它相关的配置。例如我们下面要讲到的这个配置类就是在Spring Boot中我们经常会遇到的一个配置类的形式。在这个配置类中定义了很多的关于我们引入配置如何进行全局配置的方式。
JasyptEncryptorConfigurationProperties 配置项文件
这个配置类不同于我们以往遇到的配置类,在自动配置文件中进行了使用,这个配置类中有一个构造方法是值得我们关注的。
public static JasyptEncryptorConfigurationProperties bindConfigProps(ConfigurableEnvironment environment) {final BindHandler handler = new IgnoreErrorsBindHandler(BindHandler.DEFAULT);final MutablePropertySources propertySources = environment.getPropertySources();final Binder binder = new Binder(ConfigurationPropertySources.from(propertySources),new PropertySourcesPlaceholdersResolver(propertySources),ApplicationConversionService.getSharedInstance());final JasyptEncryptorConfigurationProperties config = new JasyptEncryptorConfigurationProperties();final ResolvableType type = ResolvableType.forClass(JasyptEncryptorConfigurationProperties.class);final Annotation annotation = AnnotationUtils.findAnnotation(JasyptEncryptorConfigurationProperties.class,ConfigurationProperties.class);final Annotation[] annotations = new Annotation[]{annotation};final Bindable target = Bindable.of(type).withExistingValue(config).withAnnotations(annotations);binder.bind("jasypt.encryptor", target, handler);return config;
我们都知道,在之前的配置类使用过程中,我们都是通过@ConfigurationProperties(prefix = "jasypt.encryptor", ignoreUnknownFields = true) 这样的注解来进行属性值绑定的,但是这里这个配置类用到了BindHandler 进行数据属性绑定。由于这个文件中的内容较多。这里就不复制源码了,挑几个比较重要的属性进行说明
在这个文件中有一个属性比较重要,有很多人在使用过程中直接将加密串放到了配置文件中,就会引起各种各样的问题。
* Specify a custom {@link String} to identify* as prefix of encrypted properties. Default value is* {@code "ENC("}private String prefix = "ENC(";* Specify a custom {@link String} to identify* as suffix of encrypted properties. Default value is {@code ")"}private String suffix = ")";
从意思中可以看出,它是为每个配置项加上了一个配置前缀,也就是说,每个配置项有了这个前缀之后才会生效。
spring:datasource:url: ENC(uHOWjxcz6yEyEUnc0J99Pkmbyg5rkZcsgzH+nOnPnPF7iTu09FRlWSptxRMDF9+OEPfTZmARRm2F6hYtn6U/YeXQVO//OKEjFSNAuKaa1BvmWBqlxiHM1RERlTRqEYZ9zssgT9VNpSeSllW0J/RjNqN3xLHkfrePJTHW0a9flFTORYexuVviGWxmDrCM3qi4PTbAO5IV6bOjCB2+fFzaKI4zbJP4pLVX5uq8977roOg=)password: ENC(hMiBCsfEn0sKkLq8YXGNGWTGkLFCupAxWK0zJlr/uaGYR4U39F1fO+FmEQemmNCU)driver-class-name: com.mysql.jdbc.Driverusername: ENC(kB1Td66wuyfPW9qqQhPn/z/RjXhp3IL2H79fW6pS8T0QhNUrsP9lWaEpeIK6Qws1)
当然我们也可以修改这个配置前缀,改成我们自定义的配置前缀。
另外需要注意的一点,在进行加密的时候我们是将密钥直接配置到了配置文件中。
jasypt:encryptor:password: 123123123123123
这样做是不安全的,如果有人拿到了源码,还可以通过分析的方式获取到相关的信息。所以,最正确的做法是将我们的密钥添加到我们每次的jar命令启动的过程中如下
JAVA -jar xxxx.jar -Djasypt.encryptor.password=12312312322321
另外扩展说命名一下jasypt项目在GitHub上可以直接查询。相关更高级的使用可以在GitHub上查看。