SpringBoot配置文件中密码属性加密的实现
作者:洒脱的智障 发布时间:2022-07-08 18:32:03
本文主要介绍了SpringBoot配置文件中的明文密码如何加密保存,读取以及对于自定义的加密算法加密的参数如何保存和读取。
背景
为了安全的需要,一些重要的信息比如数据库密码不能明文保存在配置文件中,需要进行加密之后再保存。SpringBoot可以使用jasypt-spring-boot这个组件来为配置属性提供加密的支持。
集成jasypt-spring-boot到项目中
根据官方README文档,可以有三种方式集成jasypt-spring-boot到项目中。
对于SpringBoot项目,直接通过引入jasypt-spring-boot-starter,然后所有的application.properties, application-*.properties, yaml的配置文件中就可以包含加密的属性。
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>
直接引入jasypt-spring-boot,这时候需要在启动类上添加一个@EnableEncryptableProperties,然后在配置文件中可以包含有加密的字段属性。
@SpringBootApplication
@EnableEncryptableProperties
public class Application {
...
}
如果不想要整个Spring的配置文件都启用加密的字段属性,还可以自己指定对应加密的配置文件路径。也需要引入jasypt-spring-boot,同时在启动类上添加@EncryptablePropertySource注解,设置注解的value属性为需要读取的加密配置文件路径。
@SpringBootApplication
@EncryptablePropertySource({"classpath:encrypted.properties"})
public class Application {
...
}
配置文件配置加密与读取
现在知道了如何集成jasypt-spring-boot到项目中,下面就介绍一下如何加密明文的密码,以及需要如何存储在配置文件中。
首先,需要添加一个maven的插件,这个插件可以帮助我们加密我们需要的明文信息。
<plugin>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-maven-plugin</artifactId>
<version>3.0.4</version>
</plugin>
之后,执行如下的mvn命令,可以在控制台得到对于的密文。然后将配置文件中明文替换为加密后的密文。
mvn jasypt:encrypt-value -Djasypt.encryptor.password="TKzhc3fz" -Djasypt.plugin.value="123456"
-Djasypt.encryptor.password参数指定用于加密密码,我理解这个应该和秘钥类似。
-Djasypt.plugin.value参数指定需要加密的明文参数。
执行命令后,可以在控制台看到加密后的密文,密文默认是用ENC()格式包围住的,当然这个格式也可以自定义。
也可以通过这个mvn插件解密,执行如下命令,可以在控制台看到解密之后的明文。
mvn jasypt:decrypt-value -Djasypt.encryptor.password="TKzhc3fz" -Djasypt.plugin.value="ENC(Muhq57xdiHA5jJX9pX7zmNz57w4emX2D/XYIXOMEx0LYcTL7RYyadWe2J7GCi9KJ)"
在SpringBoot配置文件中,添加jasypt.encryptor.password属性,这个值和第二步生成密文的值要一样,不然解密会失败。
jasypt:
encryptor:
password: TKzhc3fz # 设置加密的password信息 类似秘钥?
test:
password: ENC(Muhq57xdiHA5jJX9pX7zmNz57w4emX2D/XYIXOMEx0LYcTL7RYyadWe2J7GCi9KJ) # 测试数据
这样在主程序启动的时候,通过@Value注解就可以自动解密配置文件中的密文信息了,这样就完成了明文的加密以及后续的读取。
工作原理简析
参照官方文档,大概的工作原理如下:
首先,在Spring容器启动之后,会遍历配置文件中的所有的配置,然后发现所有按照jasypt约定规则加密的属性,此处就是使用ENC()包围的参数,这个ENC()前缀和后缀是可以自定义的,下面会讲到。
这边主要是有两个接口,分别是EncryptablePropertyDetector、EncryptablePropertyResolver,这两个接口根据名称可以看出来一个是发现器,一个是分解器。
先来看EncryptablePropertyDetector这个接口,这个接口提供了两个方法,isEncrypted和unwrapEncryptedValue,isEncrypted方法判断是否是jasypt约定规则加密的属性,unwrapEncryptedValue方法会返回去除掉前缀和后缀的真正加密的值,可以看下该接口默认的实现DefaultPropertyDetector:
/**
* Default property detector that detects encrypted property values with the format "$prefix$encrypted_value$suffix"
* Default values are "ENC(" and ")" respectively.
*
* @author Ulises Bocchio
*/
public class DefaultPropertyDetector implements EncryptablePropertyDetector {
// 默认的前缀和后缀
private String prefix = "ENC(";
private String suffix = ")";
public DefaultPropertyDetector() {
}
public DefaultPropertyDetector(String prefix, String suffix) {
Assert.notNull(prefix, "Prefix can't be null");
Assert.notNull(suffix, "Suffix can't be null");
this.prefix = prefix;
this.suffix = suffix;
}
// 判断配置属性是否是按照jasypt约定规则加密的属性
@Override
public boolean isEncrypted(String property) {
if (property == null) {
return false;
}
final String trimmedValue = property.trim();
return (trimmedValue.startsWith(prefix) &&
trimmedValue.endsWith(suffix));
}
// 去掉默认的前缀和后缀,返回加密的值
@Override
public String unwrapEncryptedValue(String property) {
return property.substring(
prefix.length(),
(property.length() - suffix.length()));
}
}
EncryptablePropertyResolver这个接口中只提供了一个方法resolvePropertyValue,这个方法会遍历配置文件属性,判断是否是加密属性,然后进行解密返回明文。在默认实现DefaultPropertyResolver中,依赖EncryptablePropertyDetector以及StringEncryptor,真正解密的方法是写在StringEncryptor,这边具体如何解密就不详细描述了,有兴趣可以自行看下。DefaultPropertyResolver类:
/**
* @author Ulises Bocchio
*/
public class DefaultPropertyResolver implements EncryptablePropertyResolver {
private final Environment environment;
// 加密和解密的实现
private StringEncryptor encryptor;
// jasypt默认发现器
private EncryptablePropertyDetector detector;
public DefaultPropertyResolver(StringEncryptor encryptor, Environment environment) {
this(encryptor, new DefaultPropertyDetector(), environment);
}
public DefaultPropertyResolver(StringEncryptor encryptor, EncryptablePropertyDetector detector, Environment environment) {
this.environment = environment;
Assert.notNull(encryptor, "String encryptor can't be null");
Assert.notNull(detector, "Encryptable Property detector can't be null");
this.encryptor = encryptor;
this.detector = detector;
}
@Override
public String resolvePropertyValue(String value) {
// 该方法获取加密的属性,然后使用StringEncryptor解密并返回
return Optional.ofNullable(value)
.map(environment::resolvePlaceholders)
.filter(detector::isEncrypted) // 过滤加密属性
.map(resolvedValue -> {
try {
// 去除前缀和后缀获取真正加密的值
String unwrappedProperty = detector.unwrapEncryptedValue(resolvedValue.trim());
String resolvedProperty = environment.resolvePlaceholders(unwrappedProperty);
// 解密获得明文
return encryptor.decrypt(resolvedProperty);
} catch (EncryptionOperationNotPossibleException e) {
throw new DecryptionException("Unable to decrypt property: " + value + " resolved to: " + resolvedValue + ". Decryption of Properties failed, make sure encryption/decryption " +
"passwords match", e);
}
})
.orElse(value);
}
}
使用自定义的加密算法
如果不想要使用jasypt工具中的加密算法,或者内部要求使用某种特定的加密算法,jasypt-spring-boot组件也提供了自定义加解密的实现方式。上面在工作原理简析中提到了两个接口EncryptablePropertyDetector、EncryptablePropertyResolver,我们可以通过自己实现这两个接口的方式,并且指定对应的bean名称为encryptablePropertyDetector和encryptablePropertyResolver来覆盖框架提供的默认实现,完成加密算法和前缀后缀的自定义。
这边我就用base64加密算法举例,实现自定义的加密算法:
自己实现EncryptablePropertyDetector、EncryptablePropertyResolver接口,并且交给Spring管理,设置bean名称为encryptablePropertyDetector和encryptablePropertyResolver。
重写接口对应的方法。
@Component("encryptablePropertyDetector")
public class Base64EncryptablePropertyDetector implements EncryptablePropertyDetector {
private static final String PREFIX = "password:";
@Override
public boolean isEncrypted(String property) {
if (property == null) {
return false;
}
return property.startsWith(PREFIX);
}
@Override
public String unwrapEncryptedValue(String property) {
return property.substring(PREFIX.length());
}
}
@Component("encryptablePropertyResolver")
public class Base64EncryptablePropertyResolver implements EncryptablePropertyResolver {
@Autowired
private Base64EncryptablePropertyDetector encryptablePropertyDetector;
@Override
public String resolvePropertyValue(String value) {
return Optional.ofNullable(value)
.filter(encryptablePropertyDetector::isEncrypted)
.map(resolveValue -> {
final String unwrapEncryptedValue = encryptablePropertyDetector.unwrapEncryptedValue(resolveValue);
return new String(Base64.getDecoder().decode(unwrapEncryptedValue),
StandardCharsets.UTF_8);
})
.orElse(value);
}
}
配置文件中的加密属性使用自定义的前缀和后缀。这边明文先使用base64加密,之后加上“password:”前缀:
jasypt:
encryptor:
password: TKzhc3fz # 设置加密的password信息 类似秘钥?
test:
password: password:MTIzNDU2 # 测试数据
启动和读取。
来源:https://blog.csdn.net/qq_32238611/article/details/122724605
猜你喜欢
- IDEA SpringBoot项目配置热更新的步骤1.在pom.xml中添加依赖:<dependency><groupId
- 第一步:引入jar包 <dependency> <gro
- 需求是需要在TextView前端加入一个标签展示。最终效果图如下:根据效果图,很容易就能想到使用SpannableStringBuilder
- 前言Java项目开发中经常要用到分页功能,现在普遍使用SpringBoot进行快速开发,而数据层主要整合SpringDataJPA和MyBa
- hadoop做的一个简单grep程序,可从文档中提取包含某些字符串的行/* * 一个简单grep程序,可从文档中提取包含莫些字符串
- Android 微信摇一摇功能实现,最近学习传感器,就想实现摇一摇的功能,上网查了些资料,就整理下。如有错误,还请指正。开发环境Androi
- 一、NIOjava.nio全称java non-blocking IO,是指jdk1.4 及以上版本里提供的新api(New IO) ,为所
- 前言本文准确来讲是探讨如何用 Jackson 来序列化 Apache avro 对象,因为简单用 Jackson 来序列化 Apache a
- 在使用 springboot 或者 springcloud 开发的时候,通常为了保证系统的安全性,配置文件中的密码等铭感信息都会进行加密处理
- Java 本身就自带 JS 引擎,自从 Java 1.6 开始就支持了,愈来愈好。我对 js 比较熟悉,因此有个大胆的想法,为什么不用自带
- hashCode()和equals()方法可以说是Java完全面向对象的一大特色.它为我们的编程提供便利的同时也带来了很多危险.这篇文章我们
- Vector实现班级信息管理系统,供大家参考,具体内容如下代码如下:import java.util.*;public class Demo
- 什么是命名查询? Hibernate允许在映射文件中定义字符串形式的查询语句,这种查询方式成为命名查询 使用命名查询有什么好处? 由于使用H
- 由Lombok的@AllArgsConstructor注解引发的错误需求:在Service实现中写了一个方法调用第三方接口同步数据。 功能代
- #简易版1、客户发送请求经过 DisPatcherServlet 核心过滤器2、DisPatcherServlet 核心控制器在去找一个或多
- Strut2判断是否是AJAX调用1. AJAX与传统Form表单实际上,两者一般都是通过HTTP的POST请求。区
- 文章来源:csdn 作者:wangfengsdu经常听到回调函数(callback function)这个概念, 所谓回调函数,就是指这个函
- 对 Debug 的好奇初学 Java 时,我对 IDEA 的 Debug 非常好奇,不止是它能查看断点的上下文环境,更神奇的是我可以在断点处
- 反射对效率有影响 慎用!!!1.对象结构public class BusinessDept {private String yea
- 一、问题描述在使用idea Jrebel续期的时候,修改idea激活服务器地址时,遇到报错:Cannot reactivate, offli