Spring Boot 配置文件密码加密两种方案
Spring Boot 配置文件密码加密两种方案
jasypt 加解密
jasypt 是一个简单易用的加解密Java库,可以快速集成到 Spring 项目中。可以快速集成到 Spring Boot 项目中,并提供了自动配置,使用非常简单。
jasypt 库已上传到 Maven 中央仓库, 在 GitHub 上有更详细的使用说明。
jasypt 的实现原理是实现了 ApplicationContextInitializer 接口,重写了获取环境变量的方法,在容器初始化时对配置文件中的属性进行判断,若包含前后缀(ENC(的))表示是加密属性值,则进行解密并返回。
你的配置文件是不是还在使用下面这种落后的配置暴露一些密码:
jdbc.url=jdbc:mysql://127.0.0.1:3305/afei
jdbc.username=afei
jdbc.password=123456
如果是,那么继续往下看。笔者今天介绍史上最优雅加密接入方式:jasypt。
使用方式
用法一
先看用法有多简单,以springboot为例:
Application.java上增加注解@EnableEncryptableProperties(jasypt-spring-boot-starter包不需要该配置);
增加配置文件jasypt.encryptor.password = Afei@2018,这是加密的秘钥;
所有明文密码替换为ENC(加密字符串),例如ENC(XW2daxuaTftQ+F2iYPQu0g==);
引入一个MAVEN依赖;
maven坐标如下:
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot</artifactId>
<version>2.0.0</version>
</dependency>
简答的4步就搞定啦,是不是超简单?完全不需要修改任何业务代码。 其中第三步的加密字符串的生成方式为:java -cp jasypt-1.9.2.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="123456" password=Afei@2018 algorithm=PBEWithMD5AndDES
其中:
input的值就是原密码。
password的值就是参数jasypt.encryptor.password指定的值,即秘钥。
用法二
其实还有另一种更简单的姿势:
增加配置文件jasypt.encryptor.password = Afei@2018,这是加密的秘钥;
所有明文密码替换为ENC(加密字符串),例如ENC(XW2daxuaTftQ+F2iYPQu0g==);
引入一个MAVEN依赖;
maven坐标如下:
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
相比第一种用法,maven坐标有所变化。但是不需要显示增加注解@EnableEncryptableProperties;
github地址
github:https://github.com/ulisesbocchio/jasypt-spring-boot
它github首页有详细的用法说明,以及一些自定义特性,例如使用自定义的前缀和后缀取代ENC():
jasypt.encryptor.property.prefix=ENC@[
jasypt.encryptor.property.suffix=]
原理解密
既然是springboot方式集成,那么首先看jasypt-spring-boot的spring.factories的申明:
org.springframework.context.ApplicationListener=\
com.ulisesbocchio.jasyptspringboot.configuration.EnableEncryptablePropertiesBeanFactoryPostProcessor
这个类的部分核心源码如下:
public class EnableEncryptablePropertiesBeanFactoryPostProcessor implements BeanFactoryPostProcessor, ApplicationListener<ApplicationEvent>, Ordered {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 得到加密字符串的处理类(已经加密的密码通过它来解密)
EncryptablePropertyResolver propertyResolver = beanFactory.getBean(RESOLVER_BEAN_NAME, EncryptablePropertyResolver.class);
// springboot下的Environment里包含了所有我们定义的属性, 也就包含了application.properties中所有的属性
MutablePropertySources propSources = environment.getPropertySources();
// 核心,PropertySource的getProperty(String)方法委托给EncryptablePropertySourceWrapper
convertPropertySources(interceptionMode, propertyResolver, propSources);
}
@Override
public int getOrder() {
// 让这个jasypt定义的BeanFactoryPostProcessor的初始化顺序最低,即最后初始化
return Ordered.LOWEST_PRECEDENCE;
}
}
PropertySource的getProperty(String)方法委托给EncryptablePropertySourceWrapper,那么当获取属性时,实际上就是调用EncryptablePropertySourceWrapper的getProperty()方法,在这个方法里我们就能对value进行解密了。
EncryptablePropertySourceWrapper实现了接口EncryptablePropertyResolver,该定义如下:
// An interface to resolve property values that may be encrypted.
public interface EncryptablePropertyResolver {
String resolvePropertyValue(String value);
}
接口描述:
Returns the unencrypted version of the value provided free on any prefixes/suffixes or any other metadata surrounding the encrypted value. Or the actual same String if no encryption was detected.
如果通过prefixes/suffixes包裹的属性,那么返回解密后的值;
如果没有被包裹,那么返回原生的值;
实现类的实现如下:
@Override
public String resolvePropertyValue(String value) {
String actualValue = value;
// 如果value是加密的value,则进行解密。
if (detector.isEncrypted(value)) {
try {
// 解密算法核心实现
actualValue = encryptor.decrypt(detector.unwrapEncryptedValue(value.trim()));
} catch (EncryptionOperationNotPossibleException e) {
// 如果解密失败,那么抛出异常。
throw new DecryptionException("Decryption of Properties failed, make sure encryption/decryption passwords match", e);
}
}
// 没有加密的value,返回原生value即可
return actualValue;
}
判断是否是加密的逻辑很简单:(trimmedValue.startsWith(prefix) && trimmedValue.endsWith(suffix)),即只要value是以prefixe/suffixe包括,就认为是加密的value。
总结
通过对源码的分析可知jasypt的原理很简单,就是讲原本spring中PropertySource的getProperty(String)方法委托给我们自定义的实现。然后再自定义实现中,判断value是否是已经加密的value,如果是,则进行解密。如果不是,则返回原value。注意该方式由于会在bean初始化前做一些操作, 和dubbo混用是容易导致对dubbo的初始化进行预操作, 导致dubbo加载失败
druid 非对称加密
数据库连接池 Druid 自身支持对数据库密码的加密解密, 是通过 ConfigFilter 实现的,在 GitHub 有官方的指导说明。
添加依赖,
1
2
3
4
5<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>配置数据源,先用明文密码连接数据库
1
2spring.datasource.username=root
spring.datasource.password=123456编写测试代码生成非对称加密的公钥和私钥
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests { @Test
public void druidEncrypt() throws Exception {
//密码明文
String password = "123456";
System.out.println("明文密码: " + password);
String[] keyPair = ConfigTools.genKeyPair(512);
//私钥
String privateKey = keyPair[0];
//公钥
String publicKey = keyPair[1]; //用私钥加密后的密文
password = ConfigTools.encrypt(privateKey, password); System.out.println("privateKey:" + privateKey);
System.out.println("publicKey:" + publicKey); System.out.println("password:" + password); String decryptPassword = ConfigTools.decrypt(publicKey, password);
System.out.println("解密后:" + decryptPassword);
}
} #------------结果------------------
明文密码: 123456
privateKey:MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAlgDJ+BjPrmzXfnZ3DYddy7LyVqvyWkbDkVuw+hhsKPZNJRpuCjAGj9omHoj4EJ5ZMsW8emKapCPZaKKUtw1DhQIDAQABAkAgpdtPnFbXZ+kfJTmUQDox86i7JIGDFJPMN2C1jks8PsoKRuMwbSSXd3owdGyEQ28bJa3EOEdkGex+2IqsfZwBAiEAx7aclTD+MVsx9dkOcp5oWpCDpQCK0gbnyIeS5arUcyECIQDAR5Czh8ejceRRcG7yH13+FcC2GIgtLxYmi691hrBn5QIhAJuRCcPFGByGNxKUc4ahEhSJwaIEHB6iNmakBK9WNItBAiEAtXBSmTadKhxEyJyB9LOorCS2rp5Dke+GxWS2cv5f5AkCIQCwhGIq7dmtg12cK4S63zD9/SIbLMTW89ph4rgQFEsoMg== publicKey:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJYAyfgYz65s1352dw2HXcuy8lar8lpGw5FbsPoYbCj2TSUabgowBo/aJh6I+BCeWTLFvHpimqQj2WiilLcNQ4UCAwEAAQ== password:CFJ5PUOf0GLY56E27pCPI12eHFqtFzVk/XcBN49qr1e/ya/X1eN4FtGLnaEe/7VPefF40UKPgSqFMbnfPLKAiA==生成公钥和私钥,还可使用命令生成:java -cp druid-1.0.16.jar com.alibaba.druid.filter.config.ConfigTools you_password
配置文件增加解密支持,并替换明文密码
1
2
3
4
5
6
7
8
9#---------密码加密------------------------
spring.datasource.username=panda
spring.datasource.password=CFJ5PUOf0GLY56E27pCPI12eHFqtFzVk/XcBN49qr1e/ya/X1eN4FtGLnaEe/7VPefF40UKPgSqFMbnfPLKAiA==
#---------开启ConfigFilter支持-----------
spring.datasource.druid.filter.config.enabled=true
#---------设置公钥------------------------
spring.datasource.publicKey=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAINRom1IY639dDMD0FFw7zMsxRVABYGJnKxSpO84dyJgXaIkoTZkE1JaWE2/gtgli28vgM72UHf2EGhxbLZwzhsCAwEAAQ==
#---------设置连接属性---------------------
spring.datasource.druid.connection-properties=config.decrypt=true;config.decrypt.key=${spring.datasource.publicKey}重启应用, 查看数据源初始化时的连接是否成功。
再谨慎点是把测试生成密文的java文件也删除。
完整配置文件
1 |
#=============jdbc dataSource========================= |
注意:最好将密钥或私钥作为环境变量参数在执行应用的启动命令时传入,而不是放在配置文件中。
示例源码 -> GitHubhttp://www.gxitsky.com/2018/09/19/springboot-app-32-password-encryptor/
Spring Boot 配置文件密码加密两种方案的更多相关文章
- Spring Boot 整合 Shiro ,两种方式全总结!
在 Spring Boot 中做权限管理,一般来说,主流的方案是 Spring Security ,但是,仅仅从技术角度来说,也可以使用 Shiro. 今天松哥就来和大家聊聊 Spring Boot ...
- Spring Boot配置过滤器的两种方式
过滤器(Filter)是Servlet中常用的技术,可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,常用的场景有登录校验.权限控制.敏感词过滤等,下面介绍下Spring Boot配置过 ...
- spring boot 集成 Filter 的两种方式
两种方式:(两种方式同时存在时,@Bean优先@ServletComponentScan实例化,生成两个对象) 1)@ServletComponentScan注解+@WebFilter注解 2)@Be ...
- spring boot 集成 Listener 的两种方式
1)@ServletComponentScan注解+@WebListener注解 2)@Bean注解+ServletListenerRegistrationBean类
- spring boot返回Josn的两种方式
1.Controller类上加@RestController注解 2.Controller类上加@Controller注解,Action接口上加@ResponseBody注解 @Responsebod ...
- Spring Boot配置文件大全
Spring Boot配置文件大全 ############################################################# # mvc ############## ...
- Spring Boot 配置文件 bootstrap vs application 到底有什么区别?
用过 Spring Boot 的都知道在 Spring Boot 中有以下两种配置文件 bootstrap (.yml 或者 .properties) application (.yml 或者 .pr ...
- Spring Boot 配置文件详解
Spring Boot配置文件详解 Spring Boot提供了两种常用的配置文件,分别是properties文件和yml文件.他们的作用都是修改Spring Boot自动配置的默认值.相对于prop ...
- Springboot 系列(二)Spring Boot 配置文件
注意:本 Spring Boot 系列文章基于 Spring Boot 版本 v2.1.1.RELEASE 进行学习分析,版本不同可能会有细微差别. 前言 不管是通过官方提供的方式获取 Spring ...
随机推荐
- Keras 入门实例
使用Keras构建神经网络的基本工作流程主要可以分为 4个部分.(而这个用法和思路,很像是在使用Scikit-learn中的机器学习方法) Model definition → Model compi ...
- java -- eclipse运行javaweb 项目
这个是和上一个放在一块的 创建javaweb项目,要是想要创建maven项目,java项目都可以,我要和tomcat放在一块所以 就创建javaweb项目 创建项目起一个有意义的项目名 选择一个 ...
- [转帖]智能合约和 DApp
智能合约和 DApp https://www.jianshu.com/p/5e7df3902957 2018.10.08 19:50:41字数 3,403阅读 9,819 2017年11月份和2018 ...
- LaTeX 小试牛刀
跟大家分享一下正式第一次使用 LaTex 的经验,之前数学建模的时候一直想用,但没有找到合适的软件.前段时间,实验室老师让我帮忙套个 IEEE ACCESS 的模板. 尝试过 TexPad,的确 UI ...
- .NET Core如何使用NLog
1.新建ASP.NET Core项目 1.1选择项目 1.2选择.Net版本 2. 添加NLog插件 2.1 通过Nuget安装 2.2下载相关的插件 3.修改NLog配置文件 3.1添加NLog配置 ...
- golang学习笔记--接口
go 的接口类型用于定义一组行为,其中每个行为都由一个方法声明表示. 接口类型中的方法声明只有方法签名而没有方法实体,而方法签名包括且仅包括方法的名称.参数列表和结果列表. 只要一种数据类型的方法集合 ...
- .NET CORE webapi epplus 导入导出 (实习第一个月的笔记)
最近有个需求就是网页表格里面的数据导出到excel 于是从各位前辈的博客园搜了搜demo 大部分非为两类 都是用的插件NPOI和Eppluse ,因此在这里就介绍Eppluse 用法,还有就是在博 ...
- 人脸跟踪开源项目HyperFT代码算法解析及改进
一.简介 人脸识别已经成为计算机视觉领域中最热门的应用之一,其中,人脸信息处理的第一个环节便是人脸检测和人脸跟踪.人脸检测是指在输入的图像中确定所有人脸的位置.大小和姿势的过程.人脸跟踪是指在图像序列 ...
- JSP+SpringMVC框架使用WebUploader插件实现注册时候头像图片的异步上传功能
一.去官网下载webuploader文件上传插件 https://fex.baidu.com/webuploader/ 下载好后把它放到Javaweb项目的文件夹中(我放到了webcontent下面的 ...
- Java 之 可变字符序列:字符串缓冲区(StringBuilder 与 StringBuffer)
一.字符串拼接问题 由于 String 类的对象内容不可改变,所以每当进行字符串拼接时,总是会在内存中创建一个新的对象. Demo: public class StringDemo { public ...