SSM realizes mysql database account password ciphertext login function

  • 2021-12-11 09:22:49
  • OfStack

Introduction

Our company is engaged in 1 project research and development of information security confidential application, which is divided into 3 steps. Compared with 1-class company and 1-class project, More stringent requirements for information security, Leaders require that the amount of data and user's username and password information must be configured and stored in ciphertext, which involves that the username and password of the database in jdbc. properties files are also 1, and it is necessary to configure ciphertext. When connecting, it is loaded and decrypted to clear text for database connection operation. The following is the implementation process, which is divided into 3 steps.

1. Create an DESUtil class

Provide custom key, encryption and decryption methods.


package com.hzdy.DCAD.common.util;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import java.security.Key;
import java.security.SecureRandom;
/**
 * Created by Wongy on 2019/8/8.
 */
public class DESUtil {
  private static Key key;
  // Your own key 
  private static String KEY_STR = "mykey";
  static {
    try {
      KeyGenerator generator = KeyGenerator.getInstance("DES");
      SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
      secureRandom.setSeed(KEY_STR.getBytes());
      generator.init(secureRandom);
      key = generator.generateKey();
      generator = null;
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  /**
   *  Encrypts the string and returns BASE64 Encrypted string of 
   *
   * @param str
   * @return
   * @see [ Class, class # Method, class # Member ]
   */
  public static String getEncryptString(String str) {
    BASE64Encoder base64Encoder = new BASE64Encoder();
    try {
      byte[] strBytes = str.getBytes("UTF-8");
      Cipher cipher = Cipher.getInstance("DES");
      cipher.init(Cipher.ENCRYPT_MODE, key);
      byte[] encryptStrBytes = cipher.doFinal(strBytes);
      return base64Encoder.encode(encryptStrBytes);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  /**
   *  Right BASE64 Encrypt the string for decryption 
   *
   */
  public static String getDecryptString(String str) {
    BASE64Decoder base64Decoder = new BASE64Decoder();
    try {
      byte[] strBytes = base64Decoder.decodeBuffer(str);
      Cipher cipher = Cipher.getInstance("DES");
      cipher.init(Cipher.DECRYPT_MODE, key);
      byte[] encryptStrBytes = cipher.doFinal(strBytes);
      return new String(encryptStrBytes, "UTF-8");
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  public static void main(String[] args) {
    String name = "dbuser";
    String password = "waction2016";
    String encryname = getEncryptString(name);
    String encrypassword = getEncryptString(password);
    System.out.println("encryname : " + encryname);
    System.out.println("encrypassword : " + encrypassword);
    System.out.println("name : " + getDecryptString(encryname));
    System.out.println("password : " + getDecryptString(encrypassword));
  }
}

2. Create an EncryptPropertyPlaceholderConfigurer class

Establish an association with a configuration file.


package com.hzdy.DCAD.common.util;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
public class EncryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
  // Property should be associated with the configuration file's KEY Keep 1 Straight 
  private String[] encryptPropNames = {"jdbc.username", "jdbc.password"};
  @Override
  protected String convertProperty(String propertyName, String propertyValue) {
    // If you find this property in the list of encrypted properties  
    if (isEncryptProp(propertyName)) {
      String decryptValue = DESUtil.getDecryptString(propertyValue);
      System.out.println(decryptValue);
      return decryptValue;
    } else {
      return propertyValue;
    }
  }
  private boolean isEncryptProp(String propertyName) {
    for (String encryptName : encryptPropNames) {
      if (encryptName.equals(propertyName)) {
        return true;
      }
    }
    return false;
  }
}

3. Modify the configuration file jdbc. properties


# Before encryption configuration 
#jdbc.driver=com.mysql.jdbc.Driver
#jdbc.user=root
#jdbc.password=root
#jdbc.url=jdbc:mysql://localhost:3306/bookstore
# After encryption configuration 
jdbc.driver=com.mysql.jdbc.Driver
jdbc.user=Ov4j7fKiCzY=
jdbc.password=Ov4j7fKiCzY=
jdbc.url=jdbc:mysql://localhost:3306/bookstore

4. Modify the spring-content. xml configuration file


 Will spring-context In 
 <context:property-placeholder location="classpath:.properties" />
  Modify to 
 <bean class="com.hzdy.DCAD.common.util.EncryptPropertyPlaceholderConfigurer"p:locations="classpath:*.properties"/>
 // Note can only exist 1 Object that reads the configuration file bean Otherwise, the system will only read the first 

Note: If you find that the configuration ciphertext username And password Can be loaded and decrypted successfully, But at the end of the connection or ciphertext connection and error, this may involve the problem of memory preloading, project 1 start, the program will encrypt the ciphertext user name and password, even if the final decryption is successful, the last connection database read is still ciphertext, at this time we can rewrite the connection pool method, let spring-content.xml Load the rewritten connection pool method and decrypt it in advance when connecting.


package com.thinkgem.jeesite.common.encrypt;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.security.auth.callback.PasswordCallback;
import com.alibaba.druid.util.DruidPasswordCallback;
/**
 */
@SuppressWarnings("serial")
public class DruidDataSource extends com.alibaba.druid.pool.DruidDataSource {
  public PhysicalConnectionInfo createPhysicalConnection() throws SQLException {
    String url = this.getUrl();
    Properties connectProperties = getConnectProperties();
    String user;
    if (getUserCallback() != null) {
      user = getUserCallback().getName();
    } else {
      user = getUsername();
    }
    //DES Decryption 
    user = DESUtils.getDecryptString(user);
    String password = DESUtils.getDecryptString(getPassword());
    PasswordCallback passwordCallback = getPasswordCallback();
    if (passwordCallback != null) {
      if (passwordCallback instanceof DruidPasswordCallback) {
        DruidPasswordCallback druidPasswordCallback = (DruidPasswordCallback) passwordCallback;
        druidPasswordCallback.setUrl(url);
        druidPasswordCallback.setProperties(connectProperties);
      }
      char[] chars = passwordCallback.getPassword();
      if (chars != null) {
        password = new String(chars);
      }
    }
    Properties physicalConnectProperties = new Properties();
    if (connectProperties != null) {
      physicalConnectProperties.putAll(connectProperties);
    }
    if (user != null && user.length() != 0) {
      physicalConnectProperties.put("user", user);
    }
    if (password != null && password.length() != 0) {
      physicalConnectProperties.put("password", password);
    }
    Connection conn;
    long connectStartNanos = System.nanoTime();
    long connectedNanos, initedNanos, validatedNanos;
    try {
      conn = createPhysicalConnection(url, physicalConnectProperties);
      connectedNanos = System.nanoTime();
      if (conn == null) {
        throw new SQLException("connect error, url " + url + ", driverClass " + this.driverClass);
      }
      initPhysicalConnection(conn);
      initedNanos = System.nanoTime();
      validateConnection(conn);
      validatedNanos = System.nanoTime();
      setCreateError(null);
    } catch (SQLException ex) {
      setCreateError(ex);
      throw ex;
    } catch (RuntimeException ex) {
      setCreateError(ex);
      throw ex;
    } catch (Error ex) {
      createErrorCount.incrementAndGet();
      throw ex;
    } finally {
      long nano = System.nanoTime() - connectStartNanos;
      createTimespan += nano;
    }
    return new PhysicalConnectionInfo(conn, connectStartNanos, connectedNanos, initedNanos, validatedNanos);
  }
}

Modify the database connection number configuration of spring-content. xml file


# Before modification 
<!-- <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> -->
# After modification 
<bean id="dataSource"class="com.thinkgem.jeesite.common.encrypt.DruidDataSource" 
    init-method="init" destroy-method="close">
    <!--  The data source driver class does not write, Druid By default, it will be automatically based on the URL Recognition DriverClass -->
    <property name="driverClassName" value="${jdbc.driver}" />
    <!--  Basic attribute  url , user , password -->
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />

  </bean>

At this point, the database ciphertext configuration connection is completed!

Summarize


Related articles: