• Springboot实现ENC加密


    1. 为什么要用ENC加密

    以下是未经过加密的数据库配置,密码均是采用明文密码,很容易导致数据库泄露。

    spring:
     datasource:
      dynamic:
    	postgresql:
    	 url: jdbc:postgresql://127.0.0.1:5589/mypg?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai
    	 username: root
    	 password: admin          
    	 driver-class-name: org.postgresql.Driver 
    
    ...
    
    redis:
     ip: www.xxxx.top
     port: 6379
     # 密码
     pass: admin	
     # 最大实例
     max-total: 1024
     # 最大空闲实例
     max-idle: 100
     # 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。
     max-wait: 10000
     # 超时时间,单位毫秒。
     timeout: 10000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    以下是经过ENC加密之后的配置,这样之后,数据库密码安全级别就高了。

    spring:
     datasource:
      dynamic:
    	postgresql:
    	 url: jdbc:postgresql://127.0.0.1:5589/mypg?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai
    	 username: root
    	 password: ENC(2qWZr4WLw8H0nPBzMXBV9WimRfKC3pv5UVGB5mMApbINg2s83VfsYvL7XTWaUR8q)
    	 driver-class-name: org.postgresql.Driver 
    
    ...
    
    redis:
     ip: www.xxxx.top
     port: 6379
     # 密码
     pass: ENC(2qWZr4WLw8H0nPBzMXBV9WimRfKC3pv5UVGB5mMApbINg2s83VfsYvL7XTWaUR8q)	
     # 最大实例
     max-total: 1024
     # 最大空闲实例
     max-idle: 100
     # 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。
     max-wait: 10000
     # 超时时间,单位毫秒。
     timeout: 10000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    2. jasypt实现ENC加密

    1. 实现流程

    • 导入依赖:

              
              <dependency>
                  <groupId>com.github.ulisesbocchiogroupId>
                  <artifactId>jasypt-spring-boot-starterartifactId>
                  <version>3.0.2version>
              dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    • 测试类:

      import org.jasypt.encryption.StringEncryptor;
      import org.junit.Test;
      import org.junit.runner.RunWith;
      import org.springframework.boot.test.context.SpringBootTest;
      import org.springframework.test.context.junit4.SpringRunner;
      
      import javax.annotation.Resource;
      
      /**
       * @Author: chenJY
       * @Description:
       * @Date: 2022-11-18 9:19
       */
      @SpringBootTest
      @RunWith(SpringRunner.class)
      public class EncryptorTest {
          @Resource
          private StringEncryptor jasyptStringEncryptor;
      
          @Test
          public void encode() {
              System.out.println( "加密密文:" + jasyptStringEncryptor.encrypt("admin") );
              System.out.println("解密密文:" + jasyptStringEncryptor.decrypt(jasyptStringEncryptor.encrypt("admin")));
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
    • 运行测试类:

    注意: 每次运行测试类输出的加密密码都不同,但不影响其解密密文。

    • 将加密密文加入到配置文件中:
      spring:
       datasource:
        dynamic:
      	postgresql:
      	 url: jdbc:postgresql://127.0.0.1:5589/mypg?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai
      	 username: root
      	 password: ENC(2qWZr4WLw8H0nPBzMXBV9WimRfKC3pv5UVGB5mMApbINg2s83VfsYvL7XTWaUR8q)
      	 driver-class-name: org.postgresql.Driver 
      
      ...
      
      redis:
       ip: www.xxxx.top
       port: 6379
       # 密码
       pass: ENC(2qWZr4WLw8H0nPBzMXBV9WimRfKC3pv5UVGB5mMApbINg2s83VfsYvL7XTWaUR8q)
       # 最大实例
       max-total: 1024
       # 最大空闲实例
       max-idle: 100
       # 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。
       max-wait: 10000
       # 超时时间,单位毫秒。
       timeout: 10000
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
    • 重启springboot项目,能正常启动

    2. 说明

    由于springboot自动配置的特性,导入 jasypt-spring-boot 依赖包之后,不用进行过多配置,就能实现配置文件加密字段自动解密,所以特别方便。

    1. 自定义加密秘钥

    1. 盐、前缀、后缀

    可以在配置文件中自定义一个加密秘钥(盐), 来获取明文密码。

    # 加密秘钥
    jasypt:
      encryptor:
        password: Chen # 加密时的salt值
    
    • 1
    • 2
    • 3
    • 4

    自定义加密前缀、后缀: 如果不想使用 ENC来作为加密前缀,那么可以通过配置文件修改:

    # 加密秘钥
    jasypt:
      encryptor:
        password: Chen
        property:
          prefix: Chen( # 前缀
          suffix: )chen # 后缀
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    那么,密码的格式如下:

    password: Chen(2qWZr4WLw8H0nPBzMXBV9WimRfKC3pv5UVGB5mMApbINg2s83VfsYvL7XTWaUR8q)chen
    
    • 1
    2. 自定义加密方案

    配置类

    @Configuration
    public class MyEncryptorCfg {
        /**
         * @Description 自定义的加密器配置
         * @author chenJY
         * @date 2022/11/18 9:52
         * @return StringEncryptor
        */
        @Bean(name = "myStringEncryptor")
        public StringEncryptor myStringEncryptor() {
    
            PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
    
            SimpleStringPBEConfig config = new SimpleStringPBEConfig();
            config.setPassword("Chen");
            config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
            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);
    
            return encryptor;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 注意1: bean必须重命名,bean默认名是 jasyptStringEncryptor,当我们要自定义加密方案的时候,就必须重命名。

    • 注意2: 需要在配置文件中加入如下配置:

      jasypt:
        encryptor:
          bean: myStringEncryptor
      
      • 1
      • 2
      • 3

      并修改测试类:

          @Autowired
          private StringEncryptor myStringEncryptor;
      
      • 1
      • 2

    2. 部署方案

    密钥(盐值)存储说明: 本身加解密过程都是通过盐值进行处理的,所以正常情况下盐值和加密串是分开存储的。盐值应该放在系统属性、命令行或是环境变量来使用,而不是放在配置文件。

    • 程序启动 命令行参数:

      java -jar xxx.jar --jasypt.encryptor.password=Chen &
      
      • 1
    • 程序启动 环境变量:

      java -jar -Djasypt.encryptor.password=Chen xxx.jar
      
      • 1

    3. 输出密文的几种方案

    优化1.: 上面的写法是直接写死了需要加密的密码,我们可以换一种在配置文件中读取数据库密码的写法,如下:

    	import org.jasypt.encryption.StringEncryptor;
    	import org.junit.Test;
    	import org.junit.runner.RunWith;
    	import org.springframework.boot.test.context.SpringBootTest;
    	import org.springframework.test.context.junit4.SpringRunner;
    	
    	import javax.annotation.Resource;
    	
    	/**
    	 * @Author: chenJY
    	 * @Description:
    	 * @Date: 2022-11-18 9:19
    	 */
    	@SpringBootTest
    	@RunWith(SpringRunner.class)
    	public class EncryptorTest {
    		@Resource
        	private ApplicationContext applicationContext;
    
    	    @Resource
    	    private StringEncryptor jasyptStringEncryptor;
    	
    	    @Test
    	    public void encode() {
    	        Environment environment = applicationContext.getEnvironment();
            	String password = environment.getProperty("spring.datasource.dynamic.postgresql.password");
    	        System.out.println( "加密密文:" + jasyptStringEncryptor.encrypt(password) );
    	        System.out.println("解密密文:" + jasyptStringEncryptor.decrypt(jasyptStringEncryptor.encrypt(password)));
    	    }
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    优化2: 重写启动类的run(),实现每次启动项目都会输出一次加密密文

    import org.jasypt.encryption.StringEncryptor;
    import org.springframework.boot.CommandLineRunner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ApplicationContext;
    import org.springframework.core.env.Environment;
    
    @SpringBootApplication
    public class TestDemoApplication implements CommandLineRunner{
    
        @Resource
        private ApplicationContext applicationContext;
    
        @Resource
        private StringEncryptor jasyptStringEncryptor;
    
        public static void main(String[] args) {
            SpringApplication.run(TestDemoApplication.class, args);
        }
    
        @Override
        public void run(String... args) throws Exception {
            Environment environment = applicationContext.getEnvironment();
            String pwd = environment.getProperty("spring.datasource.dynamic.postgresql.password");
            // 打印解密后的结果
            System.out.println( "加密密文:" + jasyptStringEncryptor.encrypt(pwd) );
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
  • 相关阅读:
    Linux之从进程角度来理解文件描述符
    Sql 导入到 Excel 工具
    macos (M2芯片)搭建flutter环境
    时间序列-AR MA ARIMA
    Animoca Brands和Blowfish Studios推出PhantomGalaxies治理和实用通证 ASTRAFER
    Maven学习笔记
    MyBatis在循环内查询序列值重复解决方法
    nginx配置不同通信协议的端口转发
    如何删除清理Mac“其他”文件并删除它
    PyQt5快速开发与实战 9.1 使用PyInstaller打包项目生成exe文件
  • 原文地址:https://blog.csdn.net/m0_54355172/article/details/127915056