Spring Boot Implements Configuration File Encryption and Decryption Principle

Spring Boot profile encryption and decryption is as simple as that

background

Following "Return of Missing Persons, mybatis-plus 3.3.2 Release" [1], provides a very practical function, "Data Security Protection", which not only supports the configuration encryption of data sources, but also enables the encryption of sensitive information for spring boot global yml/properties files, controlling the flow of developers to a certain extent, leading to the disclosure of sensitive information.

//Data source sensitive information encryption

spring:
  datasource:
    url: mpw:qRhvCwF4GOqjessEB3G+a5okP+uXXr96wcucn2Pev6BfaoEMZ1gVpPPhdDmjQqoM
    password: mpw:Hzy5iliJbwDHhjLs1L0j6w==
    username: mpw:Xb+EgsyuYRXw7U7sBJjBpA==

//Data source sensitive information encryption

spring:
  redis:
    password: mpw:Hzy5iliJbwDHhjLs1L0j6w==

Implementation Principle

We turn over the official spring boot document to chapter 4.2.6 Spring Boot does not provide any built-in support for encrypted property values, but provides the extension point EnvironmentPostProcessor necessary to modify values contained in the Spring environment to allow environment property values to be manipulated before the application

Implementation of mybatis-plus

public class SafetyEncryptProcessor implements EnvironmentPostProcessor {

 @Override
 public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
  //Get the key from the command line
  String mpwKey = null;

  // Returns the full form of the configuration source (environment variables, command line parameters, configuration files...)
  for (PropertySource<?> ps : environment.getPropertySources()) {
   // Determine if you need to include an encrypted password, skip it without
   if (ps instanceof SimpleCommandLinePropertySource) {
    SimpleCommandLinePropertySource source = (SimpleCommandLinePropertySource) ps;
    mpwKey = source.getProperty("mpw.key");
    break;
   }
  }

  //Processing encrypted content (get the old configuration and decrypt it into the new map (key is the old key)
  HashMap<String, Object> map = new HashMap<>();
  for (PropertySource<?> ps : environment.getPropertySources()) {
   if (ps instanceof OriginTrackedMapPropertySource) {
    OriginTrackedMapPropertySource source = (OriginTrackedMapPropertySource) ps;
    for (String name : source.getPropertyNames()) {
     Object value = source.getProperty(name);
     if (value instanceof String) {
      String str = (String) value;
      if (str.startsWith("mpw:")) {
       map.put(name, AES.decrypt(str.substring(4), mpwKey));
      }
     }
    }
   }
  }
  // Put the decrypted data in the environment variable and take first priority (be careful here to override other configurations)
  if (!map.isEmpty()) {
   environment.getPropertySources().addFirst(new MapPropertySource("custom-encrypt", map));
  }
 }
}

How to load in effect

Resources/META-INF/Spring.factoriesConfigure SPI

org.springframework.boot.env.EnvironmentPostProcessor=\
  com.baomidou.mybatisplus.autoconfigure.SafetyEncryptProcessor

extend

mybatis-plus reads the startup parameters by default and can be modified here to a more secure root key store based on your needs.

Read environment variables

System.getProperty("mpw.key")

Remote Load Password Service

// For ideas here, refer to druid ConfigFilter
public Properties loadConfig(String filePath) {
      Properties properties = new Properties();

      InputStream inStream = null;
      try {
          boolean xml = false;
          if (filePath.startsWith("file://")) {
              filePath = filePath.substring("file://".length());
              inStream = getFileAsStream(filePath);
              xml = filePath.endsWith(".xml");
          } else if (filePath.startsWith("http://") || filePath.startsWith("https://")) {
              URL url = new URL(filePath);
              inStream = url.openStream();
              xml = url.getPath().endsWith(".xml");
          } else if (filePath.startsWith("classpath:")) {
              String resourcePath = filePath.substring("classpath:".length());
              inStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourcePath);
              // Should xml files also be configurable under classpath?
              xml = resourcePath.endsWith(".xml");
          } else {
              inStream = getFileAsStream(filePath);
              xml = filePath.endsWith(".xml");
          }

          if (inStream == null) {
              LOG.error("load config file error, file : " + filePath);
              return null;
          }

          if (xml) {
              properties.loadFromXML(inStream);
          } else {
              properties.load(inStream);
          }

          return properties;
      } catch (Exception ex) {
          LOG.error("load config file error, file : " + filePath, ex);
          return null;
      } finally {
          JdbcUtils.close(inStream);
      }
  }

summary

  • Configuration file encryption and decryption is implemented by custom extension EnvironmentPostProcessor
  • If you are not using the latest version of mybatis-plus in your project, you can refer to your own implementation as above, but I recommend jasypt-spring-boot-starter[2], which works like implementing an EnableEncryptablePropertySourcesPostProcessor, but supports more sophisticated encryption methods
  • You can refer to the source code for using jasypt: https://gitee.com/log4j/pig

Project Recommendation: RBAC Rights Management System for Spring Cloud, Spring Security OAuth2 Welcome

Tags: Programming Spring xml Mybatis Redis

Posted on Mon, 01 Jun 2020 21:04:17 -0400 by dspeer