environment中的value为什么要加密?
未经过加密的配置文件,密码均是采用明文密码,很容易导致信息泄露。
SpringBoot environment中的value加密代码如下
java
package com.xxx.core.encryption;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import java.util.Map;
/**
* @author HanKeQi
* @date 2023/9/4
*/
@Slf4j
public class EnableEncryptionData implements BeanFactoryPostProcessor, Ordered {
private final ConfigurableEnvironment environment;
//根据自己需求自定义
private static final String PREFIX = "ENC(";
private static final String SUFFIX = ")";
/**
* 扫描自定义配置的文件
*/
private static final String BOOTSTRAP_CONFIGURE = "bootstrap";
public EnableEncryptionData(ConfigurableEnvironment environment) {
this.environment = environment;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
MutablePropertySources propertySources = environment.getPropertySources();
for (PropertySource<?> propertySource: propertySources){
if (propertySource instanceof OriginTrackedMapPropertySource){
OriginTrackedMapPropertySource originTrackedMapPropertySource = (OriginTrackedMapPropertySource) propertySource;
String activeName = originTrackedMapPropertySource.getName();
Map<String, Object> activeSource = (Map<String, Object>)propertySources.get(activeName).getSource();
Map<String, Object> newConfigMap = Maps.newHashMap();
activeSource.forEach((k,v)->{
if (v instanceof OriginTrackedValue){
Object valueObj = ((OriginTrackedValue) v).getValue();
if (valueObj instanceof String){
String valueEncryptionStr = (String) valueObj;
if (!StringUtils.isEmpty(valueEncryptionStr) && valueEncryptionStr.startsWith(PREFIX) && valueEncryptionStr.endsWith(SUFFIX)){
try {
valueEncryptionStr = getEncryptionStr(valueEncryptionStr);
valueEncryptionStr = AesUtils.decodeStr(valueEncryptionStr, AesUtils.P_KEY);
newConfigMap.put(k, valueEncryptionStr);
return;
}catch (Exception e){
e.printStackTrace();
}
}
}
}
newConfigMap.put(k, v);
});
propertySources.replace(activeName, new OriginTrackedMapPropertySource(activeName , newConfigMap, true));
}
}
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 100;
}
/**
* 获取加密后的信息
* @param encryptionStr
* @return
*/
private static String getEncryptionStr(String encryptionStr){
encryptionStr = encryptionStr.substring(PREFIX.length());
encryptionStr = encryptionStr.substring(0, encryptionStr.length()-SUFFIX.length());
return encryptionStr;
}
}
springboot 配置Configuration
java
package com.xxx.core.encryption;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* @author HanKeQi
* @date 2022/10/30
*/
@Configuration
public class EnvironmentConfig {
@Bean
public static EnableEncryptionData enableEncryptionData(final ConfigurableEnvironment environment) {
return new EnableEncryptionData(environment);
}
}
Aes加密代码
java
package com.xxx.util.encrypt;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;
/**
* @author HanKeQi
* @date 2022/10/30
*/
@Slf4j
public class AesUtils {
public static final String IV = "vKapxbKpyptKkwuP";
private static final String P_KCS5_PADDING="AES/CBC/PKCS5Padding";
private static final String KEY = "AES";
public static final String P_KEY = "6U7Si019ireqa7vAscWBkbPClOYtn6gb";
/**
* @param content base64处理过的字符串
* @param pkey 密匙
* @return String 返回类型
* @throws Exception
* @throws
* @Title: aesDecodeStr
* @Description: 解密 失败将返回NULL
*/
public static String decodeStr(String content, String pkey) throws Exception {
try {
log.info("待解密内容: {}", content);
byte[] base64DecodeStr = Base64.decodeBase64(content);
byte[] aesDecode = decode(base64DecodeStr, pkey);
if (aesDecode == null) {
return null;
}
String result;
result = new String(aesDecode, "UTF-8");
return result;
} catch (Exception e) {
throw new Exception("解密异常");
}
}
/**
* 解密 128位
*
* @param content 解密前的byte数组
* @param pkey 密匙
* @return result 解密后的byte数组
* @throws Exception
*/
public static byte[] decode(byte[] content, String pkey,String IV) throws Exception {
SecretKeySpec skey = new SecretKeySpec(pkey.getBytes(), KEY);
IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));
//创建密码器
Cipher cipher = Cipher.getInstance(P_KCS5_PADDING);
//初始化解密器
cipher.init(Cipher.DECRYPT_MODE, skey, iv);
byte[] result = cipher.doFinal(content);
// 解密
return result;
}
public static byte[] decode(byte[] content, String pkey) throws Exception {
return decode(content,pkey,IV);
}
/**
* @param content 加密前原内容
* @param pkey 长度为16个字符,128位
* @return base64EncodeStr aes加密完成后内容
* @throws
* @Title: aesEncryptStr
* @Description: aes对称加密
*/
public static String encryptStr(String content, String pkey) {
byte[] aesEncrypt = encrypt(content, pkey);
String base64EncodeStr = Base64.encodeBase64String(aesEncrypt);
return base64EncodeStr;
}
/**
* 加密 128位
*
* @param content 需要加密的原内容
* @param pkey 密匙
* @return
*/
public static byte[] encrypt(String content, String pkey, String iv) {
try {
//SecretKey secretKey = generateKey(pkey);
//byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec skey = new SecretKeySpec(pkey.getBytes(), KEY);
Cipher cipher = Cipher.getInstance(P_KCS5_PADDING);// "算法/加密/填充"
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, skey, ivParameterSpec);//初始化加密器
byte[] encrypted = cipher.doFinal(content.getBytes("UTF-8"));
return encrypted; // 加密
} catch (Exception e) {
log.info("encrypt() method error:", e);
}
return null;
}
public static byte[] encrypt(String content, String pkey) {
return encrypt(content,pkey, IV);
}
}
配置文件
yaml
spring:
redis:
database: 1
host: redis.commons.svc.cluster.local
port: 6379
# 使用了 AesUtils.encryptStr("ADoZH2Gw6KEw51c3Mk", P_KEY);
password: ENC(hji+7pHQpX0f0/dVncyT/leJ6sWHiCUlFq7LdDJjo1s=)