1。问题背景使用过SpringBoot框架的应该都知道,SpringBoot有一个主应用配置文件,里面涉及敏感的配置信息,比如各种中间件的连接用户名和密码信息,以及各种第三方KEY、秘钥等。如果将这种敏感信息直接放在配置文件中,肯定是不安全的,甚至在很多行业和领域(如:支付领域)也是不合规的,所以需要对敏感配置信息进行保护在春季启动。那么,你还在让你的SpringBoot系统裸奔吗?如果是,不妨看看本文栈长分享的4个方法,让你的系统不再裸奔!二、配置中心(支持自动解密)我觉得也要看你的架构。如果使用外部第三方配置中心(支持自动解密的),可以将所有配置信息存储在配置中心,比如SpringCloud生态中的配置中心。然后你可以使用内置的加密和解密机制来保护敏感信息:spring:datasource:username:'{cipher}t1s293294187a31f35dea15e8bafaf7774532xxcc20d6d6dd0dfa5ae753d6836'需要加密的内容以{cipher}开头,用单引号括起来。具体可以参考《Spring Cloud 配置中心内容加密》这篇文章,SpringBoot的配置文件只存放了一些无??关紧要的配置。你用的是哪个配置中心?您是否为配置加密和解密付费?欢迎分享!如果没有使用配置中心怎么办?比如在传统的SpringBootMVC项目中,所有的代码和配置几乎都在同一个项目中。Boot中最核心的配置文件是application.yml(.properties)文件,那么如何保护敏感的配置信息呢?继续往下看!3、数据库机制可以将所有配置信息存储在数据库中,并在系统启动时全部加载到内存中。存储时,敏感信息采用对称加密算法加密存储,加载时自动解密到内存。这是最传统的配置管理方式。其实你也可以把它理解成一个原始简单的配置中心,只是功能没有那么强大,因为现在很多配置中心都是将配置存储在数据库中,然后提供一系列的配置管理能力。这里的数据库可以是关系型数据库(MySQL、Oracle)、内存数据库(Redis、Zookeeper)等,都是常用的中间件技术。第四,自定义加解密机制取决于此时的使用程度。如果只是简单的数据库连接池信息,那么可以考虑使用现有系统中的对称加密算法,结合连接池数据源类实现自定义加解密机制,比如我们可以模仿SpringCloud加密机制:先用系统已有的对称加密算法加密数据库连接信息:spring:datasource:username:'{cipher}t1s293294187a31f35dea15e8bafaf7774532xxcc20d6d6dd0dfa5ae753d6836'排除SpringBoot系统自带的数据源自动配置,然后组装自己的数据源SpringBean。判断获取到的配置值是否以标识符{cipher}开头,如果是则使用系统约定的对称加密算法解密,然后设置数据源,例如://示例代码@BeanpublicDataSourcedataSource(){数据源dataSource=newDruidDataSource();//解密字符串username=this.getUsername();if(username.startWith('{cipher}')){username=Encrypt.decrypt(username,this.getKey()))}dataSource.setUsername(username);...returndataSource;}SpringBoot的基础就不介绍了。我推荐这个实用教程。教程和示例源码已上传:https://github.com/javastacks/spring-boot-best-practice。这很容易使用,不需要任何额外的第三方包。如果你也使用自定义数据源,或者这种手动加解密机制可以满足保护其他敏感配置的需求,那么这个方案供你参考。上面介绍的自定义加解密机制可以满足一般需求。如果是SpringBoot自动配置场景,比如数据源自动配置,Redis自动配置等,系统启动时默认会自动配置这个。我们不能干涉手动解密。这种情况下,我们需要考虑在框架层进行介入,在SpringBoot框架读取配置时进行拦截解密,或者使用第三方框架,比较常用的是:JasyptSpringBoot。5.JasyptSpringBootJasyptSpringBoot是一个为SpringBoot项目中的属性提供加密支持的框架。支持的版本为SpringBoot1.x~2.x。stackleader写文章的时候,现在已经有1.8K+的Star数了,人气还是很高的。开源地址:https://github.com/ulisesbocchio/jasypt-spring-boot本开源项目更新及时。最新更新支持SpringBoot2.5.4!这里stackmanager免费给大家分享一份SpringBoot的学习笔记,理论和实战都很齐全,助你快速上手SpringBoot。一、JasyptSpringBoot实战JasyptSpringBoot有3种集成方式:(1)如果开启了SpringBoot的自动配置(使用@SpringBootApplication或@EnableAutoConfiguration注解):只需添加jasypt-spring-boot-starter依赖,即可在整个Spring环境中启用可加密属性;(2)添加jasypt-spring-boot依赖,在Spring主配置类中添加@EnableEncryptableProperties注解,将在整个Spring环境中启用可加密属性;(3)添加jasypt-spring-boot依赖,使用@EncrytablePropertySource注解声明各个可加密参数,仅适用于独立配置参数的加解密;一般SpringBoot都会开启自动配置,然后排除个别的自动配置,所以很少会禁用所有的自动配置,否则用SpringBoot是没有意义的。这里我们使用第一种集成方式进行演示。1.1引入依赖核心依赖:com.github.ulisesbocchiojasypt-spring-boot-starter3.0.4Maven插件(可选):com.github.ulisesbocchiojasypt-maven-plugin${jasypt-spring-boot.version}1.2添加keyjasypt:encryptor:password:G9w0BAQEFAASCBKYwggSiAgEAAoIBAQCproperty:prefix:"ENC@["suffix:"]"这个jasypt.encryptor.password参数吧是必须的,相当于Salt(盐),保证密码安全,prefix和prefix是用户自定义的密码字符串标识,如果不配置,默认为:ENC(...)。1.3敏感信息加密/***来源微信公众号:Java技术栈*作者:栈长*/@Slf4j@RunWith(SpringRunner.class)@SpringBootTestpublicclassJasyptTest{@AutowiredprivateStringEncryptorstringEncryptor;/***来源微信公众号:Java技术栈*作者:栈长*/@Testpublicvoidencrypt(){StringusernameEnc=stringEncryptor.encrypt("javastack");StringpasswordEnc=stringEncryptor.encrypt("javastack.cn");日志。info("测试用户名加密为{}",usernameEnc);log.info("测试密码加密为{}",passwordEnc);log.info("测试用户名是{}",stringEncryptor.decrypt(usernameEnc));log.info("测试密码为{}",stringEncryptor.decrypt(passwordEnc));}}这里我注入了一个StringEncryptor,它的类结构图如下:如果没有自定义StringEncryptor,JEncrySporBoot的自动配置会默认创建一个St实例,直接使用。其构造函数的默认值如下:KeyRequiredDefaultValuejasypt.encryptor.passwordTrue-jasypt.encryptor.algorithmFalsePBEWITHHMACSHA512ANDAES_256jasypt.encryptor.key-obtention-iterationsFalse1000jasypt.encryptor.pool-sizeFalse1jasypt.encryptor.provider-nameFalseSunJCEjasypt.encryptor.provider-类名Falsenulljasypt.encryptor.salt-generator-classnameFalseorg.jasypt.salt.RandomSaltGeneratorjasypt.encryptor.iv-generator-classnameFalseorg.jasypt.iv.encryptorsIvGeneratorsstring-output-typeFalsebase64jasypt.encryptor.proxy-property-sourcesFalsefalsejasypt.encryptor.skip-property-sourcesFalseemptylist然后运行测试用例,看到测试结果:加解密成功!!另外,通过DEBUG调试可以看到是一个DefaultLazyEncryptor实例:当然也支持自定义Encryptor。如果需要,您可以自己定制。如果不想使用测试的方式生成密文,也可以使用Maven插件。这就是您需要添加Maven插件(可选)的原因。用法如下:mvnjasypt:encrypt-value-Djasypt.encryptor.password="G9w0BAQEFAASCBKYwggSiAgEAAoIBAQC"-Djasypt.plugin.value="javastack"1.4敏感信息解密将上??一步生成的密文填入应用配置文件:javastack:用户名:ENC@[K4DsOasic/5Cvu2Y6Ca5dyaw2+eejgqRfhDWB0itMWRONrIN+wLy3xkGbSfYxQ1b]密码:ENC@[UeZWoPt3ZhSs2wPUAKTF21dgnhzimB+FNNiQjpJoPEhwYzI5WH3IWbog@W]n上面的自定义配置注解ENCholder+5Rholder然后写个程序试试打印出来:/***来源微信公众号:Java技术栈*作者:栈长*/@Slf4j@SpringBootApplicationpublicclassApplication{@Value("${javastack.username}")私有字符串用户名;@Value("${javastack.password}")私有字符串密码;/***来源微信公众号:Java技术栈*作者:栈管理员*/publicstaticvoidmain(String[]args){SpringApplication.run(Application.class);}/***来源微信公众号:Java技术栈*作者:栈长*/@BeanpublicCommandLineRunnercommandLineRunner(){return(args)->{log.info("javastack.username={}",username);log.info("javastack.password={}",密码);};}}栈长写了一个CommandLineRunner,在系统启动后打印出密文原文。如果需要做任何处理,直接注入打印看看是不是纯文本就可以了。系统启动后:结果正常,自动解密成功。本教程所有实战源码已上传至本仓库:https://github.com/javastacks/spring-boot-best-practice2。密钥安全我们将Jasypt密钥(密码)保存在应用配置文件中,这样敏感信息还在项目代码中,不太安全。建议传入命令行参数,比如在IDEA中设置:如果是生产环境,可以传入命令:java-Djasypt.encryptor.password=password-jarxx.jar甚至可以在配置服务器环境变量,因为StringEncryptor可以通过系统参数、配置文件、命令行参数、环境变量等来构造。这样一来,SpringBoot中的配置信息就完全安全了!JasyptSpringBoot的功能远不止于此,实际功能更强大。这里,栈长只介绍简单的应用。更多自定义需求,可以参考官方文档。那里有更详细的教程。三、JasyptSpringBoot的原理JasyptSpringBoot注册了一个Spring后处理器,修改SpringEnvironment中包含的所有PropertySource对象,按照Jasypt的配置约定对属性进行加解密。来一波源码:源码有点复杂。一路找到了解密器DefaultPropertyResolver,然后它也注入了StringEncryptor实例。当获取配置时,它会对其进行解密,然后返回。另外这个Resolver还支持自定义,有兴趣的可以深入研究一下。综上所述,今天栈长介绍了4种SpringBoot保护敏感配置信息的方法。总结一下:配置中心(支持自动加解密)自定义加解密机制数据库机制JasyptSpringBoot(第三方加解密方案)总之是敏感信息,不应该放在SpringBoot的配置文件中。如果必须放置,则必须对其进行加密。这四种解决方案各有各的应用场景,需要结合公司现有的架构和系统规模进行取舍。本教程所有实际源码已上传至本仓库:https://github.com/javastacks/spring-boot-best-practice。本文转载自微信公众号《Java技术栈》,可通过以下二维码关注。转载本文请联系Java技术栈公众号。