基于spring boot框架的配置信息加密方法总结

1、前言

目前的Java项目中,Spring boot框架已经成为不二选择,无论是传统分布式系统还是基于Spring cloud的微服务系统,都需要Spring boot作为底层开发框架。系统的开发,大量定制化的配置信息都集中在类似application.yml这样的配置文件中,其中就包括数据库链接口令等敏感信息。由于系统安装到服务器后,配置文件对所有可访问用户都是开放的,如果敏感信息明文写在配置文件中,泄露风险很高,必须对配置文件中的敏感信息进行加密。

2、加密思路

对配置信息进行加密的基本思路是:
(1)将密文写入到配置文件中,并提供加密标识(可以不提供,通过配置信息的关键字区分,例如读取到password的属性值后,默认该值是加密的)
(2)指定密钥的存储位置
(3)在使用配置信息前,获取密钥,并对密文进行解密,将解密后的值赋予对应配置项。

3、属性值的加解密过程

配置文件中属性分为两类,一种是自定义属性,是开发过程中根据需要写入到配置文件中;另一种是非自定义属性,是框架或其他组件约定的属性,像"jdbc.url"、"jdbc.password"这样的。

3.1 自定义属性加解密过程

自定义属性需要手动加载进JavaBean后使用,对配置信息的解密过程可以在加载过程中进行。
基本步骤是:
(1) 使用加密工具加密机密信息,将密文写入到配置文件中;
(2)实现配置信息加载逻辑 ,在加载过程中调用解密工具,将密文译成明文;
获取密钥的过程参见4.4小节.
下面是配置信息加载逻辑的代码示例。

3.1.1 配置文件内容(YAML文件)

  testProps:
  # 'xxxxx'为密文
   testPassword: xxxxxx
3.1.2 配置信息加载逻辑
package com.test;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component //将TestProps类注册到容器中
@ConfigurationProperties(prefix = "testProps")
public class TestProps {
   private String testPassword;
   public void setTestPassword(String testPassword) {
       // 使用解密工具解密,密钥通过解密工具获取,加解密实现细节不是本文重点,不再展开介绍
       String decryptPwd = CustomPropsDecryptUtil.decrypt(testPassword)
       this.testPassword = decryptPwd;
   }
}

3.2 非自定义属性的加解密过程

非自定义属性的加载过程由Spring boot框架自动进行,对这些属性值的解密操作可以在加载配置文件时进行,示例代码如下:

3.2.1 配置文件内容(YAML文件)
spring:
 # spring datasource
 datasource:
   #账号配置
   url: jdbc:mysql://127.0.0.1:3306/dbName?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
   username: userXX
   password: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
   driver-class-name: com.mysql.cj.jdbc.Driver
3.2.2 在配置文件加载过程中解密
import java.util.Properties; 
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

/**
* 配置文件解密核心类
*/
public class CustomPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {

   protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
   		throws BeansException {
   	try{
   		String password = props.getProperty("spring.datasource.password");
   		if (password != null) {
   			props.setProperty("spring.datasource.password",
   					CustomPropsDecryUtil.decrypt(password));
   		}
   
   		super.processProperties(beanFactory, props);
   	} catch (Exception e) {
   		e.printStackTrace();
   		throw new BeanInitializationException(e.getMessage());
   	}
   }
}

4、JASYPT加密工具

系统单独实现配置信息的加解密过程,有很多好处,比如加解密工具是自己实现的,可以根据需要调整加解密算法。但是也有很多缺点,比较突出的就是加解密实现比较繁琐且具有定制化特征,复用麻烦。如果不是对加密过程有特殊要求,可以使用现有的一些开源加密工具,像比较流行jasypt-spring-boot-starter。

4.1 引入依赖

项目引入工具后,完成基本配置后,框架会自动完成对配置信息的解密过程,省去了手动解密的工作。下面是依赖引入代码 :

<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>2.1.0</version>
</dependency>

JASYPT工具提供了非常丰富定制功能,包括自定义加\解密器、自定义加密标识的前缀和后缀等功能,本文对这部分内容不展开介绍,需要的可以参考JASYPT官方文档。

4.2 对属性进行加密

4.2.1 命令行加密(推荐)

在项目中引入jasypt工具后,本地maven仓库会生成对应的工具jar包,可以调用jar包对属相值进行加密,示例命令如下:

java -cp jasypt-1.9.2.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI password=1Qaz0oKm algorithm=PBEWithMD5AndDES input=root

输出结果如下:

----ENVIRONMENT-----------------
Runtime: Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 25.171-b11
----ARGUMENTS-------------------
input: root
algorithm: PBEWithMD5AndDES
password: 1Qaz0oKm 
----OUTPUT----------------------
NZmLHOOHX0SEjc285iG9YQ==

4.2.2 工具类加密

除了使用命令行加密外,也可以在项目中实现加密工具,调用JASYPT工具进行加密,不推荐使用此方法,因为需要将加密使用的盐值明文写入到代码中,如果盐值泄露,对方就能使用JASYPT工具解密出加密配置信息。如果使用,强烈建议在项目打包时,排除掉工具类。工具类示例代码,网上有很多,这里不再展示。

4.3 密文写入到配置文件

将密文写入到配置文件,配置时需要指定加密标识,方便框架识别出是否需要解密。配置示例如下 :

 spring:
  # spring datasource
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/dbName?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
    username: userXX
    # 'ENC('为默认加密标识前缀 ,')'为默认加密标识后缀
    password: ENC(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)
    driver-class-name: com.mysql.cj.jdbc.Driver

4.4 指定JASYPT工具获取SALT方法

JASYPT工具获取SALT的方式有很多种,常见的有以下几种:
(1)系统配置文件中获取。
网上很多文章都是将salt放在系统配置文件中,这种方式非常危险,让配置信息的加密形同虚设,不推荐使用这种方式。
(2)系统启动参数指定
在系统启动时,通过启动命令,指定salt的值,例如:java -Djasypt.encryptor.password=e9fbdb2d3b21 -jar xxxDemo.jar。这种方式比较安全,而且系统只在系统启动时提供一次,泄露的风险比较低,推荐使用。
(3)服务器的环境变量里配置
可以在系统安装服务器中,配置环境变量,指定salt的值。这种方式存在风险。
(4)外置文件存储salt值
外置文件存储salt值得思路是,salt值存储在系统外的其他位置中,修改系统启动逻辑,在系统启动时,从外置文件中获取slat值,这种方式比较安全,但是操作繁琐,实现代价较高。

5. 总结

配置文件中的信息加密,对业务功能没有帮助,而且会增加研发工作量,在部分系统中,登录口令等敏感信息都是明文写在配置文件中的。从系统安全性考虑,这样的做法是比较严重的错误,一旦安装服务器登录口令被破解,系统就完全暴露给入侵者。本文介绍了在Spring boot框架下,对配置文件加密的实现方法,可以为研发实现提供参考。

6. 参考文章

  1. Spring Boot2.X 配置文件自动解密读取
  2. 采用DES加密方式对properties配置文件敏感信息加密处理;
  3. SpringBoot项目MySQL配置文件密码加密(jasypt);
  4. 使用Jasypt对SpringBoot配置文件加密;
  5. springboot的配置文件;
  6. SPRINGBOOT 配置文件加解密;
posted @ 2020-02-29 15:19  donfaquir  阅读(2729)  评论(0编辑  收藏  举报