Springboot implements value encryption in custom environment

Why should the value in the environment be encrypted?

For unencrypted configuration files, the passwords are plaintext passwords, which can easily lead to information leakage.

The value encryption code in the springboot environment is as follows


package com.xxx.core.encryption;

import com.xxx.util.encrypt.AesUtils;
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.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 xxx
 * @date 2022/10/30
 */
@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) {
    
    
            String name = propertySource.getName();
            if (!name.startsWith(BOOTSTRAP_CONFIGURE)){
    
    
                continue;
            }

            Object object = propertySource.getSource();
            if (object instanceof Map){
    
    
                Map<String, Object> source = (Map<String, Object>) propertySource.getSource();
                source.forEach((k, v) -> {
    
    
                    if (v instanceof String){
    
    
                        String valueEncryptionStr = (String) v;
                        if (!StringUtils.isEmpty(valueEncryptionStr) && valueEncryptionStr.startsWith(PREFIX) && valueEncryptionStr.endsWith(SUFFIX)){
    
    
                            try {
    
    
                                valueEncryptionStr = getEncryptionStr(valueEncryptionStr);
                                //根据自己需求自定义解密算吗
                                valueEncryptionStr = AesUtils.decodeStr(valueEncryptionStr, AesUtils.P_KEY);
                                source.put(k, valueEncryptionStr);
                            }catch (Exception e){
    
    
                                e.printStackTrace();
                            }
                        }
                    }
                });
            }
        }
    }

    @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 Configuration

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 encryption code

package com.fulan.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);
    }


}

configuration file

spring:
  redis:
    database: 1
    host: redis.commons.svc.cluster.local
    port: 6379
    # 使用了 AesUtils.encryptStr("ADoZH2Gw6KEw51c3Mk", P_KEY);
    password: ENC(hji+7pHQpX0f0/dVncyT/leJ6sWHiCUlFq7LdDJjo1s=)

Guess you like

Origin blog.csdn.net/helenyqa/article/details/130480921