许多项目里会对配置文件中的敏高文件进行加密处理,避免了信息泄露问题。在springboot项目里,可以通过引入jasypt进行密码密文存放
jasypt使用
1.引入jasypt-spring-boot-starter包
2.配置信息
jasypt:
encryptor:
algorithm: PBEWithHMACSHA512AndAES_256
password: 123456 //salt
或将password放在启动行参数里
3.启动项添加注解
4.生成密文
可以通过网上的密码工具生成,也可以使用jasypt生成
AES256TextEncryptor stringEncryptor = new AES256TextEncryptor();
stringEncryptor.setPassword("123456"); //salt
String encrypt = stringEncryptor.encrypt("test"); //加密 test为你的密码
String decrypt = stringEncryptor.decrypt(encrypt); //解密
5.将生成的encrypt放到原来的密码处并用ENC()包裹即可,ENC()可通过jasypt.encryptor.algorithm.property.prefix/suffix进行配置
test: ENC(sdjflskdjfsjdflksdjalfjdslkfjksdjfkldsjkfsf) //此处放上面生成的encrypt
jasypt:
encryptor:
algorithm: PBEWithHMACSHA512AndAES_256
property:
prefix: #默认为ENC(
suffix: #默认为)
与Dubbo联用
它会存在一个问题,就是无法对dubbo的配置进行加密,解决方法如下:
方法
将下面文件添加到项目里,目前仅支持PBEWithHMACSHA512AndAES_256,如需要支持其他,可自行在TODO处添加处理逻辑
//JasyptPreparedEnvListener.java package test.listener; import org.jasypt.util.text.AES256TextEncryptor; import org.springframework.boot.context.config.ConfigFileApplicationListener; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.SmartApplicationListener; import org.springframework.core.Ordered; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.PropertySource; import java.util.Iterator; import java.util.Map; import java.util.stream.Stream; public class JasyptPreparedEnvListener implements SmartApplicationListener, Ordered { private String getSalt(ConfigurableEnvironment env ){ String salt = env.getProperty("jasypt.encryptor.password"); if(salt == null || salt.isBlank()) { return null; } return salt; } private String[] getConfigAllows(ConfigurableEnvironment env ){ String rst = env.getProperty("jasypt.encryptor.property.config.allows"); String[] rstArr; if(rst == null || rst.isBlank()) { rstArr = new String[]{"dubbo."}; return rstArr; }else{ rstArr = Stream.of(rst.split(",")).map(val->val+".").toArray(String[]::new); } return rstArr; } private String getConfigPrefix(ConfigurableEnvironment env ){ String rst = env.getProperty("jasypt.encryptor.property.config.prefix"); if(rst == null || rst.isBlank()) { rst = env.getProperty("jasypt.encryptor.property.prefix"); } if(rst == null || rst.isBlank()) { return "ENC("; } return rst; } private String getConfigSuffix(ConfigurableEnvironment env ){ String rst = env.getProperty("jasypt.encryptor.property.config.suffix"); if(rst == null || rst.isBlank()) { rst = env.getProperty("jasypt.encryptor.property.suffix"); } if(rst == null || rst.isBlank()) { return ")"; } return rst; } private boolean shouldDecrypted(String[] allows,String value){ if(value == null || value.isBlank()){ return false; } String trimValue = value.trim(); boolean rst = false; for(String allow : allows){ if(trimValue.startsWith(allow)){ rst = true; } } return rst; } private boolean isEncrypted(String value,String prefix,String suffix){ if(value == null || value.isBlank()){ return false; } String trimValue = value.trim(); return trimValue.startsWith(prefix) && trimValue.endsWith(suffix); } private String unwrapEncryptedValue(String value,String prefix,String suffix){ return value.substring(prefix.length(),value.length() - suffix.length()); } private String getAlgorithm(ConfigurableEnvironment env){ String rst = env.getProperty("jasypt.encryptor.algorithm"); if(rst == null || rst.isBlank()) { return "PBEWithHMACSHA512AndAES_256"; } return rst; } private Object getDecryptor(ConfigurableEnvironment env){ String algorithm = getAlgorithm(env); Object obj = null; if(algorithm.equals("PBEWithHMACSHA512AndAES_256")){ String salt = getSalt(env); if(salt != null){ obj = new AES256TextEncryptor(); ((AES256TextEncryptor)obj).setPassword(salt); } }//add other decryptor logic here return obj; } private String decrypt(ConfigurableEnvironment env,Object decryptpr,String value){ String algorithm = getAlgorithm(env); if(algorithm.equals("PBEWithHMACSHA512AndAES_256")){ AES256TextEncryptor aes256TextEncryptor = (AES256TextEncryptor)decryptpr; try{ return aes256TextEncryptor.decrypt(value); }catch (Exception e){ System.out.println("decrypt failed: " + e); return value; } } //add other decryptor logic here return value; } @Override public void onApplicationEvent(ApplicationEvent applicationEvent) { ConfigurableEnvironment env = ((ApplicationEnvironmentPreparedEvent)applicationEvent).getEnvironment(); // 1. get decryptor Object decryptor = getDecryptor(env); if(decryptor == null){ return; } String configPrefix = getConfigPrefix(env); String configSuffix = getConfigSuffix(env); String[] configAllows = getConfigAllows(env); // 2. loop property Iterator<PropertySource<?>> iterator = env.getPropertySources().iterator(); while (iterator.hasNext()) { PropertySource<?> source = iterator.next(); Object o = source.getSource(); if (o instanceof Map) { for (Map.Entry<String, Object> entry : ((Map<String, Object>) o).entrySet()) { String key = entry.getKey(); String value = env.getProperty(key); if (shouldDecrypted(configAllows,key) && isEncrypted(value, configPrefix, configSuffix)) { //3.解密 String newValue = decrypt(env, decryptor, unwrapEncryptedValue(value, configPrefix, configSuffix)); System.setProperty(key, newValue); } } } } } @Override public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) { return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(aClass); } @Override public int getOrder() { return ConfigFileApplicationListener.DEFAULT_ORDER + 1; } }
- 添加配置(三选一即可)
application.properties(多个监听器用,隔开)
context.listener.classes: test.listener.JasyptPreparedEnvListener
application.yml(多个监听器用,隔开)
context:
listener:
classes: test.listener.JasyptPreparedEnvListener
启动项里api添加
SpringApplication app = new SpringApplication(App.class);
app.addListeners(new JasyptPreparedEnvListener());
app.run(args);
- 将需要密文存储的地方使用ENC()包裹即可
dubbo:
registries:
password: ENC(fdsfsdfsd)
修改配置
jasypt:
encryptor:
algorithm: PBEWithHMACSHA512AndAES_256
property:
config:
prefix: #默认取jasypt.encryptor.property.prefix的配置,如果没有则为ENC(
suffix: #同prefix
allows: #允许更新的值的prefix 默认为dubbo 多个使用,隔开 (例dubbo或dubbo.registries或dubbo,mail)
它的思路就是在Springboot的ApplicationEnvironmentPreparedEvent事件里对配置文件信息进行处理
ApplicationEnvironmentPreparedEvent: spring boot 对应Enviroment已经准备完毕,但此时上下文context还没有创建。在该监听中获取到ConfigurableEnvironment后可以对配置信息做操作,例如:修改默认的配置信息,增加额外的配置信息等等
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。