背景
对于springboot项目,项目中依赖的配置如:数据库密码、中间件密码等都是明文保存在配置文件中的。
这种方式存在很大的风险,在企业的安全扫描中也通过不了。为了安全的需要,所以要对配置文件进行加密处理。
使用方式
集成 jasypt
pom 引入依赖
<!-- 配置文件加密 -->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
application.yml 中增加
# 秘钥 不支持中文
jasypt:
encryptor:
password: fandf
编写测试类 pom 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
package com.fandf.demo;
import org.jasypt.encryption.StringEncryptor;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
/**
* @author fandongfeng
*/
@SpringBootTest(classes = DemoApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class JasyptTest {
@Resource
private StringEncryptor stringEncryptor;
/**
* example:
* redis:password= 123
* 123 加密后的内容:
* 修改后的配置文件
* redis:password= ENC(QvHbj+BCPR/bnSdDuNKzpoB3Kw9Pvm1bEIaSqlD5Ohhp8rPKBUcj0f5V+QqWsPP0)
* ENC(mVTvp4IddqdaYGqPl9lCQbzM3H/b0B6l)
*/
@Test
public void encrypt() {
String encrypt = stringEncryptor.encrypt("UUID");
//UUID 加密后的内容:AkZs6tdmJojZe74vfIi5BRXbUvqkBiNQrn3RO22GeqW9sBjbNuIcNz+GdqkqJ8DQ
System.out.println(" UUID 加密后的内容:" + encrypt);
String decrypt = stringEncryptor.decrypt(encrypt);
System.out.println("解密后的内容:" + decrypt);
}
}
修改配置文件
fdf:
trace:
enable: true
style: ENC(AkZs6tdmJojZe74vfIi5BRXbUvqkBiNQrn3RO22GeqW9sBjbNuIcNz+GdqkqJ8DQ)
启动项目,看下效果
原理
源码链接:https://github.com/ulisesbocchio/jasypt-spring-boot
查看其自动引入的类
查看 JasyptSpringBootAutoConfiguration 类
EnableEncryptablePropertiesConfiguration
@Configuration
@Import({EncryptablePropertyResolverConfiguration.class, CachingConfiguration.class})
public class EnableEncryptablePropertiesConfiguration {
private static final Logger log = LoggerFactory.getLogger(EnableEncryptablePropertiesConfiguration.class);
public EnableEncryptablePropertiesConfiguration() {
}
@Bean
public static EnableEncryptablePropertiesBeanFactoryPostProcessor enableEncryptablePropertySourcesPostProcessor(ConfigurableEnvironment environment, EncryptablePropertySourceConverter converter) {
return new EnableEncryptablePropertiesBeanFactoryPostProcessor(environment, converter);
}
}
查看 EnableEncryptablePropertiesBeanFactoryPostProcessor
public class EnableEncryptablePropertiesBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered {
private static final Logger log = LoggerFactory.getLogger(EnableEncryptablePropertiesBeanFactoryPostProcessor.class);
private final ConfigurableEnvironment environment;
private final EncryptablePropertySourceConverter converter;
public EnableEncryptablePropertiesBeanFactoryPostProcessor(ConfigurableEnvironment environment, EncryptablePropertySourceConverter converter) {
this.environment = environment;
this.converter = converter;
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
log.info("Post-processing PropertySource instances");
MutablePropertySources propSources = this.environment.getPropertySources();
this.converter.convertPropertySources(propSources);
}
public int getOrder() {
return 2147483547;
}
}
这里就基本看明白了,通过 bean 工厂后置处理器,在加载配置文件后进行操作。
对配置文件进行解密这边主要是有两个接口,分别是 EncryptablePropertyDetector、EncryptablePropertyResolver,这两个接口根据名称可以看出来一个是发现器,一个是分解器。
先来看看 EncryptablePropertyDetector
public interface EncryptablePropertyDetector {
boolean isEncrypted(String var1);
String unwrapEncryptedValue(String var1);
}
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约定规则加密的属性
public boolean isEncrypted(String property) {
if (property == null) {
return false;
} else {
String trimmedValue = property.trim();
return trimmedValue.startsWith(this.prefix) && trimmedValue.endsWith(this.suffix);
}
}
//去掉前缀和后缀,返回加密的值
public String unwrapEncryptedValue(String property) {
return property.substring(this.prefix.length(), property.length() - this.suffix.length());
}
}
接着看 EncryptablePropertyResolver
public interface EncryptablePropertyResolver {
String resolvePropertyValue(String var1);
}
//默认实现类
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);
}
}
更多技术文章可以查看我的博客地址:http://fandf.top
原文始发于微信公众号(好好学技术):springboot配置文件加密
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/219680.html