0、问题背景
用 Spring Boot 框架的小伙伴应该都晓得,Spring Boot 有个次要的 applicaiton 配置文件,那就会波及到敏感配置信息,比方各种中间件的连贯用户名明码信息、以及各种第三方的 KEY、密钥等。
这种敏感信息如果间接放在配置文件中必定是不平安的,甚至在很多行业及畛域(比方:领取畛域)都是不合规的,所以须要爱护 Spring Boot 中的敏感配置信息。
所以,你还在让你的 Spring Boot 零碎裸奔吗?如果是,那无妨看看本文中栈长分享的 4 种办法,让你的零碎不再裸奔!
1、配置核心(反对主动解密)
我感觉还得看大家的架构状况,如果应用了外置的第三方配置核心(反对主动解密的那种),就能够把所有的配置信息存储在配置核心,比方 Spring Cloud 生态中的配置核心,那么能够应用自带的加、解密机制爱护敏感信息:
spring:
datasource:
username: '{cipher}t1s293294187a31f35dea15e8bafaf7774532xxcc20d6d6dd0dfa5ae753d6836'
须要加密的内容以 {cipher}
结尾标识,并留神要应用单引号包起来,具体的细节能够参考《Spring Cloud 配置核心内容加密》这篇文章,Spring Boot 配置文件就只存储一些无关紧要的配置。
大家用的哪款配置核心呢?领取配置加解密吗?欢送分享!
如果没有用到配置核心呢 ?
比如说传统的 Spring Boot 的 MVC 我的项目,所有的代码、配置都简直在同一个我的项目中,Spring Boot 中的外围配置文件就是 application.yml(.properties)文件,那要怎么爱护敏感配置信息呢?持续往下看!
2、数据库机制
能够把所有配置信息存储到数据库,系统启动的时候全副加载进内存。存储的时候,敏感信息以对称加密算法进行加密存储,而后加载的时候主动解密到内存。
这是最传统的配置管理办法,其实你也能够了解为一个原始的、繁难的配置核心,只是性能不那么弱小而已,因为当初很多配置核心就是把配置放在数据库中进行存储,而后提供一系列的配置管理性能。
这里的数据库能够是关系数据库(MySQL、Oracle)、内存数据库(Redis、Zookeeper)等,这是广泛用的比拟多的中间件技术。
3、自定义加解密机制
这时候也要看应用的水平,如果只是简略的数据库连接池信息,那么能够思考应用现有零碎中的对称加密算法,再联合连接池数据源类实现自定义加解密机制,比方咱们能够模拟 Spring Cloud 加密机制:
先用零碎已有的对称加密算法对数据库连贯信息加密:
spring:
datasource:
username: '{cipher}t1s293294187a31f35dea15e8bafaf7774532xxcc20d6d6dd0dfa5ae753d6836'
排除 Spring Boot 零碎自带的数据源主动配置,而后自行组装数据源 Spring Bean。
判断获取的配置值是否以 {cipher}
这个标识结尾,如果是,则用零碎约定的对称加密算法进行解密,而后再设置数据源,比方:
// 示例代码
@Bean
public DataSource dataSource(){DataSource dataSource = new DruidDataSource();
// 解密
String username = this.getUsername();
if (username.startWith('{cipher}')){username = Encrypt.decrypt(username, this.getKey()))
}
dataSource.setUsername(username);
...
return dataSource;
}
Spring Boot 根底就不介绍了,举荐下这个实战教程,教程和示例源码都曾经传了:https://github.com/javastacks…
这种应用简略,不必额定引入任何第三方包,如果大家也是应用的自定义数据源,或者这种手动加解密机制能够满足爱护其余敏感配置的需要,那么这种计划供大家参考。
下面介绍的自定义的加解密机制能够满足个别的需要,如果是 Spring Boot 主动配置的场景,比方数据源主动配置,Redis 主动配置,等等,这种在系统启动的时候就会默认主动配置,咱们人工解密干涉不到。
像这种状况,咱们就须要思考染指框架层了,在 Spring Boot 框架读取配置的时候进行拦挡解密,或者应用第三方的框架,用的比拟多是:Jasypt Spring Boot。
4、Jasypt Spring Boot
Jasypt Spring Boot 是一个专门为 Spring Boot 我的项目中的属性提供加密反对的框架,反对的版本为 Spring Boot 1.x ~ 2.x,栈长写文之时,当初曾经有 1.8K+ 的 Star 数了,还是挺受欢迎的。
开源地址:
https://github.com/ulisesbocc…
这个开源我的项目更新也挺及时的,最新更新的,已反对 Spring Boot 2.5.4!
这里栈长再收费分享你一份 Spring Boot 学习笔记,实践和实战都十分齐全,助你疾速搞定 Spring Boot。
4.1 Jasypt Spring Boot 实战
Jasypt Spring Boot 有 3 种集成办法:
1、 如果开启了 Spring Boot 的主动配置 (应用了 @SpringBootApplication 或者 @EnableAutoConfiguration 注解):只须要增加 jasypt-spring-boot-starter
依赖即可,这种会在整个 Spring Environment 中启用可加密属性;
2、增加 jasypt-spring-boot
依赖,同时在 Spring 次要配置类上增加 @EnableEncryptableProperties
注解,这种会在整个 Spring Environment 中启用可加密属性;
3、增加 jasypt-spring-boot
依赖,应用 @EncrytablePropertySource 注解申明各个可加密的参数上,这种只实用于独立配置参数加解密;
个别的 Spring Boot 都会开启主动配置,而后再排除个别的主动配置,所以很少会有全副禁用主动配置的状况,不然应用 Spring Boot 的意义不大,这里咱们应用第 1 种集成形式进行演示。
4.1.1 引入依赖
外围依赖:
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>
Maven 插件(可选)
<build>
<plugins>
<plugin>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-maven-plugin</artifactId>
<version>${jasypt-spring-boot.version}</version>
</plugin>
</plugins>
</build>
4.1.2 增加密钥
jasypt:
encryptor:
password: G9w0BAQEFAASCBKYwggSiAgEAAoIBAQC
property:
prefix: "ENC@["
suffix: "]"
这个 jasypt.encryptor.password
参数是必须的,相当于 Salt
(盐),以保障明码安全性,prefix
和 prefix
是自定义的明码串标识,不配置默认为:ENC(...)
。
4.1.3 敏感信息加密
/**
* 起源微信公众号:Java 技术栈
* 作者:栈长
*/
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class JasyptTest {
@Autowired
private StringEncryptor stringEncryptor;
/**
* 起源微信公众号:Java 技术栈
* 作者:栈长
*/
@Test
public void encrypt() {String usernameEnc = stringEncryptor.encrypt("javastack");
String passwordEnc = stringEncryptor.encrypt("javastack.cn");
log.info("test username encrypt is {}", usernameEnc);
log.info("test password encrypt is {}", passwordEnc);
log.info("test username is {}", stringEncryptor.decrypt(usernameEnc));
log.info("test password is {}", stringEncryptor.decrypt(passwordEnc));
}
}
这里我注入了一个 StringEncryptor
,其类结构图如下:
如果以后没有自定义 StringEncryptor,Jasypt Spring Boot 的主动配置会默认创立一个 StringEncryptor 实例,间接用就行了,其结构器默认值如下:
Key | Required | Default Value |
---|---|---|
jasypt.encryptor.password | True | – |
jasypt.encryptor.algorithm | False | PBEWITHHMACSHA512ANDAES_256 |
jasypt.encryptor.key-obtention-iterations | False | 1000 |
jasypt.encryptor.pool-size | False | 1 |
jasypt.encryptor.provider-name | False | SunJCE |
jasypt.encryptor.provider-class-name | False | null |
jasypt.encryptor.salt-generator-classname | False | org.jasypt.salt.RandomSaltGenerator |
jasypt.encryptor.iv-generator-classname | False | org.jasypt.iv.RandomIvGenerator |
jasypt.encryptor.string-output-type | False | base64 |
jasypt.encryptor.proxy-property-sources | False | false |
jasypt.encryptor.skip-property-sources | False | empty list |
而后运行测试用例来看下测试后果:
加解密胜利!!
另外,通过 DEBUG 调试能够看到是一个 DefaultLazyEncryptor
实例:
当然也反对自定义的 Encryptor,有须要的能够自行定制。
如果不想用测试这种办法生成密文,也能够应用 Maven 插件,这就是后面为什么要加 Maven 插件(可选)的起因,应用形式如下:
mvn jasypt:encrypt-value -Djasypt.encryptor.password=”G9w0BAQEFAASCBKYwggSiAgEAAoIBAQC” -Djasypt.plugin.value=”javastack”
4.1.4 敏感信息解密
将上一步生成的密文填充到 application 配置文件中:
javastack:
username: ENC@[K4DsOasic/5Cvu2Y6Ca5dyaw2+eejgqRfhDWB0itMWRONrIN+wLy3xkGbSfYxQ1b]
password: ENC@[UeZWoPt3ZhSs2wPUAKTF21dgnhzimB+FNNiQjpJoPEhwYzI5WH3IWboZ5Wn+5Rgf]
留神 ENC@[]
这个占位符是下面进行自定义配置的。
而后再写一个程序尝试打印进去:
/** * 起源微信公众号:Java 技术栈 * 作者:栈长 */@Slf4j@SpringBootApplicationpublic class Application {@Value("${javastack.username}") private String username; @Value("${javastack.password}") private String password; /** * 起源微信公众号:Java 技术栈 * 作者:栈长 */ public static void main(String[] args) {SpringApplication.run(Application.class); } /** * 起源微信公众号:Java 技术栈 * 作者:栈长 */ @Bean public CommandLineRunner commandLineRunner() { return (args) -> {log.info("javastack.username = {}", username); log.info("javastack.password = {}", password); }; }}
栈长写了一个 CommandLineRunner
,在系统启动之后将密文的原文打印进去,不须要做任何解决,间接注入、打印就行,看是不是明文。
系统启动之后:
后果失常,主动解密胜利。
本节教程所有实战源码已上传到这个仓库:
https://github.com/javastacks…
大家能够一键 Star,继续更新~
4.2 密钥安全性
咱们把 Jasypt 密钥(password)寄存在 application 配置文件中,这样敏感信息还是在我的项目代码中,也不是太平安,倡议通过命令行参数的形式传入,如在 IDEA 中这样设置:
如果是生产环境,能够通过命令的形式传入:
java -Djasypt.encryptor.password=password -jar xx.jar
甚至还能够配置在服务器环境变量中,因为 StringEncryptor 能够通过 零碎参数、配置文件、命令行参数、环境变量 等等形式进行结构。
这样 Spring Boot 中的配置信息就彻底平安了!
Jasypt Spring Boot 性能远不止如此,理论性能要更弱小,这里栈长只是介绍了简略的使用,更多的自定义的需要大家能够参考官网文档,那里有更具体的教程。
4.3 Jasypt Spring Boot 原理
Jasypt Spring Boot 它注册了一个 Spring 后处理器,它润饰蕴含在 Spring Environment 中的所有 PropertySource 对象,并依照 Jasypt 的配置约定对属性进行加解密。
来跟一波源码:
源码有点简单,一路找到了 DefaultPropertyResolver
这个解密器,而后它也是注入了 StringEncryptor
这个实例,获取配置时,会进行解密后再返回。
另外,这个 Resolver 也是反对自定义的,有趣味的能够深入研究下。
总结
好了,明天栈长介绍了 Spring Boot 爱护敏感配置信息的 4 种办法,总结一下:
- 配置核心(反对主动加解密)
- 自定义加解密机制
- 数据库机制
- Jasypt Spring Boot(第三方加解密计划)
总之敏感信息不要放在 Spring Boot 配置文件中,肯定要放,就肯定要加密,这 4 种计划各有各的利用场景,要联合公司现有的架构和零碎规模作出衡量,另外之前写的这篇《分布式系统中解决参数配置的 4 种计划》也供大家参考下。
本节教程所有实战源码已上传到这个仓库:
https://github.com/javastacks…
欢送 Star 关注学习,后续会继续更新 Spring Boot 实战教程。
好了,明天的分享就到这里了,前面栈长会分享更多好玩的 Java 技术和最新的技术资讯,关注公众号 Java 技术栈第一工夫推送,我也将支流 Java 面试题和参考答案都整顿好了,在公众号后盾回复关键字 “ 面试 ” 进行刷题。
版权申明: 本文系公众号 “Java 技术栈 ” 原创,转载、援用本文内容请注明出处,剽窃、洗稿一律投诉侵权,后果自负,并保留追究其法律责任的权力。
近期热文举荐:
1.1,000+ 道 Java 面试题及答案整顿 (2022 最新版)
2. 劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4. 别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!
5.《Java 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!