The spring project configuration file does not allow the solution of plaintext passwords (jasypt usage method)

I. Introduction

For security reasons, plaintext passwords are not allowed in java project configuration files;

In order to solve this problem, you can use jasyptthis jar package. This jar package can encrypt and decrypt strings. After importing into the project, just write the encrypted password in the configuration file. When the project starts, this jar package will encrypt and decrypt the password. Decryption does not affect the normal use of the project.

Plaintext passwords are also not allowed in the java class, and this jar package can also be used for encryption and decryption.

Two, the solution

1. In the spring project, pom.xmlintroduce:

<!-- https://mvnrepository.com/artifact/org.jasypt/jasypt -->
<dependency>
    <groupId>org.jasypt</groupId>
    <artifactId>jasypt</artifactId>
    <version>1.9.3</version>
</dependency>

2. Write an encryption and decryption tool class ENC_Util.java, the sample is as follows:


import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;


public class ENC_Util {

    private static final String SALT = "mysalt";

    /**
     * jasypt-1.9.3 加解密工具类( jasypt-spring-boot-starter 是 2.1.2 )
     */

    private static final String PBEWITHMD5ANDDES = "PBEWithMD5AndDES";
    private static final String PBEWITHHMACSHA512ANDAES_256 = "PBEWITHHMACSHA512ANDAES_256";

    public static String encryptWithMD5(String plainText) {
        return encryptWithMD5(plainText,SALT);
    }

    public static String decryptWithMD5(String plainText) {
        //自己的解密方法,解密时,需要把ENC()去掉才行
        if(plainText == null || plainText.length()<=5){
            return "";
        }else{
            plainText = plainText.substring(4,plainText.length()-1);
        }
        return decryptWithMD5(plainText,SALT);
    }

    /**
     * Jasyp2.x 加密(PBEWithMD5AndDES)
     * @param		 plainText      待加密的原文
     * @param		 factor         加密秘钥
     * @return       java.lang.String
     */
    public static String encryptWithMD5(String plainText, String factor) {
        // 1. 创建加解密工具实例
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        // 2. 加解密配置
        EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();
        config.setAlgorithm(PBEWITHMD5ANDDES);
        config.setPassword(factor);
        encryptor.setConfig(config);
        // 3. 加密
        return encryptor.encrypt(plainText);
    }

    /**
     * Jaspy2.x 解密(PBEWithMD5AndDES)
     * @param		 encryptedText      待解密密文
     * @param		 factor             解密秘钥
     * @return       java.lang.String
     */
    public static String decryptWithMD5(String encryptedText, String factor) {
        // 1. 创建加解密工具实例
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        // 2. 加解密配置
        EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();
        config.setAlgorithm(PBEWITHMD5ANDDES);
        config.setPassword(factor);
        encryptor.setConfig(config);
        // 3. 解密
        return encryptor.decrypt(encryptedText);
    }

    /**
     * Jasyp3.x 加密(PBEWITHHMACSHA512ANDAES_256)
     * @param		 plainText  待加密的原文
     * @param		 factor     加密秘钥
     * @return       java.lang.String
     */
    public static String encryptWithSHA512(String plainText, String factor) {
        // 1. 创建加解密工具实例
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        // 2. 加解密配置
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword(factor);
        config.setAlgorithm(PBEWITHHMACSHA512ANDAES_256);
        // 为减少配置文件的书写,以下都是 Jasyp 3.x 版本,配置文件默认配置
        config.setKeyObtentionIterations( "1000");
        config.setPoolSize("1");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
        // 3. 加密
        return encryptor.encrypt(plainText);
    }

    /**
     * Jaspy3.x 解密(PBEWITHHMACSHA512ANDAES_256)
     * @param		 encryptedText  待解密密文
     * @param		 factor         解密秘钥
     * @return       java.lang.String
     */
    public static String decryptWithSHA512(String encryptedText, String factor) {
        // 1. 创建加解密工具实例
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        // 2. 加解密配置
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword(factor);
        config.setAlgorithm(PBEWITHHMACSHA512ANDAES_256);
        // 为减少配置文件的书写,以下都是 Jasyp 3.x 版本,配置文件默认配置
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
        // 3. 解密
        return encryptor.decrypt(encryptedText);
    }

    public static void main(String[] args) {
        String plainText = "3s";
        //这个每次跑的结果不一样
        String encryptWithMD5Str = encryptWithMD5(plainText, SALT);
        //虽然不一样,这个也能正常执行
        String decryptWithMD5Str = decryptWithMD5(encryptWithMD5Str, SALT);

        System.out.println("加密前:"+plainText);
        System.out.println("加密后:"+encryptWithMD5Str);
        System.out.println("解密后:"+decryptWithMD5Str);

        //String encryptWithSHA512Str = encryptWithSHA512(plainText, factor);
        //String decryptWithSHA512Str = decryptWithSHA512(encryptWithSHA512Str, factor);

        //System.out.println("采用SHA512加密前原文密文:" + encryptWithSHA512Str);
        //System.out.println("采用SHA512解密后密文原文:" + decryptWithSHA512Str);
    }

}

You can execute the main method of this class, change it plainTextto the content to be encrypted, and the encrypted content can be generated after execution;
you can modify SALTthe variable, which is the salt value for encryption and decryption.

3. Customize a configuration file parsing class ENC_PropertyPlaceholderConfigurerand inherit it PropertyPlaceholderConfigurer, which implements the decryption operation of the encrypted content of the configuration file. A sample is as follows:



import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ENC_PropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {

    /**
     * 将包含ENC()的value进行转换
     */
    @Override
    protected String convertProperty(String propertyName, String propertyValue) {
        //其实是 ^ENC\(.+\)$ 
        //以ENC开头,包含(,中间1-N个字符,结尾是)的,就匹配成功
        Pattern pattern = Pattern.compile("^ENC\\(.+\\)$");
        Matcher matcher= pattern.matcher(propertyValue);
        if (matcher.find()){
            //如果是这样的格式,说明是加密后的,就返回解密后的内容
            return  ENC_Util.decryptWithMD5(propertyValue);
        }else{
            //否则直接返回即可,不做处理
            return propertyValue;
        }
    }

}

4. Configure the custom parsing class into the spring xml file, so that the class written by yourself can be used when the project starts.

Take my project as an example,

When the project starts, it will generally be loaded first web.xml, and there will generally be:

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath:META-INF/app_config/context/context-*.xml
		</param-value>
	</context-param>

The meaning of this section is that all the files resourcesin the folder starting with will be loaded ; (after the project is packaged into a war package, it will be )META-INF/app_config/context/context-xml
项目名\WEB-INF\classes\META-INF\app_config\context\

Therefore, taking my project as an example, you can add such a configuration in the xml file under this path:

	<bean name="enc_propertyConfiger" class="com.xxx.config.ENC_PropertyPlaceholderConfigurer">
		<property name="ignoreResourceNotFound" value="true" />
		<property name="locations">
			<list>
				<value>META-INF/app_config/properties/db1.properties</value>
				<value>META-INF/app_config/properties/db2.properties</value>
			</list>
		</property>
	</bean>

Among them, db1.properties and db2.properties contain information such as account passwords for database connections.

5. Modify propertiesthe configuration file and replace the plaintext password with ENC(密文)the format. The sample is as follows:
The ciphertext can be executed ENC_Util.java.

jdbc_driverClass=com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://127.0.0.1:3306/mydb
jdbc_username=root
#jdbc_password=root
#用秘钥mysalt,加密就是这个,解密就是root(注意每次加密后得到的结果都不一样,不过解密得到的结果都一样)
jdbc_password=ENC(l44BhMR+f40JBsP5euOKKA==)

6. If some plaintext passwords are configured in the xml file, you can use EL expressions ${}to make it read the value in properties, for example:

<bean name="secDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
		<property name="url" value="${jdbc_url}" />
		<property name="username" value="${jdbc_username}" />
		<property name="password" value="${jdbc_password}" />
		<property name="driverClassName" value="${jdbc_driverClass}" />
		...

Note that because the custom configuration file parsing class is configured in step 4, the scanned properties file will be loaded into the project, and the xml file can use the EL expression to get the value.

First check whether the default configuration file parsing class has been configured in the project, search for class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer", if it already exists, delete this and replace it with custom (Customized can be encrypted and decrypted)

7. If the SALT variable in ENC_Util.java is not allowed to exist, then you can add the secret key in the startup parameters, and then use it in the xml file ${}. (I haven't tried this yet, but it should work)

https://bbs.csdn.net/topics/392314029
通过 jvm 启动参数 参数 -DXXXXX, 这个XXXXX在springxml里面可以直接通过 ${XXXXX} 引用

-Dmy_salt='mysalt'

Then you can:

	<bean name="enc_propertyConfiger" class="com.taikang.udp.timer.common.util.config.ENC_PropertyPlaceholderConfigurer">
	    <property name="mySALT" value="${my_salt}" />
		
		<property name="ignoreResourceNotFound" value="true" />
		<property name="locations">
			<list>
				<value>META-INF/app_config/properties/uat/secondaryDB.properties</value>
			</list>
		</property>
	</bean>
public class ENC_PropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {

    //这样这个值就注入了,后续可以用
    private String mySALT;
    
    public void setMySALT(String mySALT){
        this.mySALT = mySALT;
    }

3. Summary

1.jasypt can encrypt and decrypt strings

2. In the spring project, the encrypted password can be configured in the properties file

3. Then you can customize and PropertyPlaceholderConfigurerdecrypt when reading properties

4. In xml, it can ${}be used to use the decrypted password and other configuration information

5. In java, you can use jasypt to decrypt the string and use it

6. You can pass in global variables in the tomcat startup parameters as the secret key for jasypt encryption and decryption (if you are not allowed to configure it in the code), and then use it in xml to get it and inject it into ${}java for use

Guess you like

Origin blog.csdn.net/BHSZZY/article/details/130251647