环境:Springboot2.4.12 + Spring Cloud Context 3.0.5
SpringBoot配置文件中的内容通常情况下是明文显示,安全性就比较低一些。在application.properties或application.yml,比如数据库配置信息的密码,Redis配置的密码等都是通过明文配置的,为了提供系统整体的安全性,我们需要对这些敏感的信息进行加密处理,这样即便你难道了我的配置信息你也获取不到有价值的信息。
在Springboot下我们可以通过如下两种方式简单的实现敏感信息的加密处理:
关于Jasypt网上介绍的很多,这里不做介绍。这里我们主要只讲Spring Cloud Context中提供的这个EnvironmentPostprocessor。
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-context</artifactId> <version>3.0.5</version></dependency>
应用配置
encrypt: key: 123456789 #密钥 salt: abcdef #加密的内容使用了加盐处理---spring: cloud: decrypt-environment-post-processor: enabled: true #开启解密功能
现在需要对custom.password这样的一个key值进行加密处理
custom: password: 123456
首先需要对这明文生成加密的内容,如下方式:
public static void main(String[] args) throws Exception { String key = "123456789" ; String salt = "abcdef" ; String text = "123123" ; KeyProperties keyProperties = new KeyProperties() ; keyProperties.setKey(key) ; keyProperties.setSalt(salt) ; String result = TextEncryptorUtils.createTextEncryptor(keyProperties, null).encrypt(text) ; System.out.println(result) ;}
通过上面的代码就可以生成加密信息,接下来就是将加密后的内容配置到配置文件中
custom: password: "{cipher}2a483a44681006be6f0730b1acb45325c6bd20abe37369ef4fdb52c2e194a365"
注意:这里的内容是有格式要求的必须是:{cipher}开头。这里还有一点需要注意有可能你运行上面的代码会报错,报错信息应该是 “Illegal key size” (非法的密钥大小),比如:AES加密算法在默认JDK(Sun的JDK)配置情况下支持的密钥大小是128位,一旦超过就会报错,这时候你需要安装Java加密扩展(JCE)策略文件。下面提供了3个版本的JCE策略文件。
Java 6 JCE:
https://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html
Java 7 JCE
https://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
Java 8 JCE
https://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
下载对应的版本后将其解压如下位置:
JCE策略文件安装目录
以上操作完成以后在运行上面的程序就能输出结果了,然后将结果替换配置文件内容即可。
接下来测试:
@Value("${custom.password}")public String pwd ; @GetMapping("/pwd")public String pwd() { return pwd ;}
正确的输出了我们的内容
关于EnvironmentPostProcessor接口编写完成以后都会进行配置,我们上面引入的context包就对DecryptEnvironmentPostProcessor进行了配置:
配置EnvironmentPostProcessor
public class DecryptEnvironmentPostProcessor extends AbstractEnvironmentDecrypt implements EnvironmentPostProcessor, Ordered { @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { // 判断是否开启了功能 if (bootstrapEnabled(environment) || useLegacyProcessing(environment) || !isEnabled(environment)) { return; } // 如果环境中不存在TextEncryptor那么也不会开启 if (!ClassUtils.isPresent("org.springframework.security.crypto.encrypt.TextEncryptor", null)) { return; } // 获取当前环境下的所有配置属性 MutablePropertySources propertySources = environment.getPropertySources(); environment.getPropertySources().remove(DECRYPTED_PROPERTY_SOURCE_NAME); // 解密所有的配置属性,这里也就是入口了 Map<String, Object> map = TextEncryptorUtils.decrypt(this, environment, propertySources); if (!map.isEmpty()) { // 将解密后的配置添加到环境中(addFirst 表示了添加到具有最高优先级的给定属性源对象) propertySources.addFirst(new SystemEnvironmentPropertySource(DECRYPTED_PROPERTY_SOURCE_NAME, map)); } } protected Boolean isEnabled(ConfigurableEnvironment environment) { // 获取配置属性值,是否开启功能 return environment.getProperty("spring.cloud.decrypt-environment-post-processor.enabled", Boolean.class, true); }}
解密配置
public abstract class TextEncryptorUtils { static Map<String, Object> decrypt(AbstractEnvironmentDecrypt decryptor, ConfigurableEnvironment environment, MutablePropertySources propertySources) { // 获取加解密服务接口 TextEncryptor encryptor = getTextEncryptor(decryptor, environment); return decryptor.decrypt(encryptor, propertySources); } static TextEncryptor getTextEncryptor(AbstractEnvironmentDecrypt decryptor, ConfigurableEnvironment environment) { Binder binder = Binder.get(environment); // 将属性配置以 ‘encrypt’开头的都绑定到KeyProperties对象中 KeyProperties keyProperties = binder.bind(KeyProperties.PREFIX, KeyProperties.class).orElseGet(KeyProperties::new); // 检查是否配置了encrypt.key 等核心的信息 if (TextEncryptorUtils.keysConfigured(keyProperties)) { decryptor.setFailOnError(keyProperties.isFailOnError()); // 检查是否当前CLASSPATH中是否存在RsaSecretEncryptor if (ClassUtils.isPresent("org.springframework.security.rsa.crypto.RsaSecretEncryptor", null)) { RsaProperties rsaProperties = binder.bind(RsaProperties.PREFIX, RsaProperties.class).orElseGet(RsaProperties::new); return TextEncryptorUtils.createTextEncryptor(keyProperties, rsaProperties); } // 如果你没有使用及配置Rsa相关的,那么就会在这里创建加解密服务接口,这里跟踪了下使用的是AES加密算法 return new EncryptorFactory(keyProperties.getSalt()).create(keyProperties.getKey()); } // no keys configured return new TextEncryptorUtils.FailsafeTextEncryptor(); }}
获取到了加解密服务接口以后,接下来就是对配置属性进行解密操作。
public class AbstractEnvironmentDecrypt { public static final String ENCRYPTED_PROPERTY_PREFIX = "{cipher}"; protected Map<String, Object> decrypt(TextEncryptor encryptor, PropertySources propertySources) { Map<String, Object> properties = merge(propertySources); // 解密处理 decrypt(encryptor, properties); return properties; } protected void decrypt(TextEncryptor encryptor, Map<String, Object> properties) { // 开始替换所有以{cipher}开头的属性值 properties.replaceAll((key, value) -> { String valueString = value.toString(); if (!valueString.startsWith(ENCRYPTED_PROPERTY_PREFIX)) { return value; } // 解密数据, key 配置属性的key, valueString要解密的数据 return decrypt(encryptor, key, valueString); }); } protected String decrypt(TextEncryptor encryptor, String key, String original) { // 截取{cipher}之后的内容 String value = original.substring(ENCRYPTED_PROPERTY_PREFIX.length()); try { // 解密数据 value = encryptor.decrypt(value); return value; } catch (Exception e) { // ... return ""; } }}
整个源码处理还是非常简单的。
本文链接:http://www.28at.com/showinfo-26-6190-0.htmlSpringBoot中的敏感信息的配置进行加密处理,这种方式你知道吗?
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
下一篇: Go 语言中排序的三种方法