首页 > 其他分享 >Spring 配置文件加密

Spring 配置文件加密

时间:2024-07-07 17:08:06浏览次数:5  
标签:加密 配置文件 Spring springframework import org config com public

前文

在某些场景下,使用 Spring 作为开发组件时,不可避免地需要使用到配置文件,然而,对于配置文件中的某些敏感数据(如密码等信息字段),如果使用明文的方式,则可能在一定程度上导致信息泄露。为此,需要一种有效的方式来对这些字段进行加密处理,当前主流的一种加密方式就是 Jasypt

基本使用

对于主流的 Spring 应用程序,现在基本上都是采用 Spring-Boot 的方式进行开发,因此我们可以很方便地以 starter 的方式引入 Jasypt 对应的 starter 依赖

<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.5</version> <!-- 具体以 Maven 仓库的为准 -->
</dependency>

然后,需要在对应的应用程序配置文件中配置 Jasypt 的相关配置属性:

jasypt:
  encryptor:
    # 解密时需要用到的对称密码
    password: 1234567
    # 解密时使用的解密算法,具体可以查看 com.sun.crypto.provider.PBEKeyFactory 的相关子类
    algorithm: PBEWithHmacSHA224AndAES_128
    # 一些通用的配置属性,如过滤字段是否需要解密、需要解密的字段的格式等
    property:
      # 如果字段需要解密,则这个字段的值的开始前缀
      prefix: ENC(
      # 如果字段需要解密,则这个字段的值的后缀
      suffix: )
    # 加密时的重 Hash 次数
    key-obtention-iterations: 1000

然而,对于需要解密的字段,需要按照解密的规则对其进行加密处理,Jasypt 已经提供了现有的工具类,只需要传入我们需要的参数进行加密即可:

import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig;
import org.jasypt.iv.RandomIvGenerator;
import org.jasypt.salt.RandomSaltGenerator;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;

import javax.crypto.SecretKeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;

@SpringBootTest(classes = {DemoApplication.class})
public class SimpleEncryptTest {

    private final static Logger log = LoggerFactory.getLogger(SimpleEncryptTest.class);

    // 注意,这里的 Config 必须与上文配置文件中的一致,否则会导致解密结果与最初值不一致
    private static EnvironmentStringPBEConfig pbeConfig() {
        String password = "1234567"; // 这里的密码需要与配置文件里的相对应

        final EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();

        config.setPassword(password); // 当前对称加密算法需要的基本密码,而不是需要转换的文本

        /*
            具体对称加密算法,目前系统提供了 com.sun.crypto.provider.PBEKeyFactory 子类相关的算法
         */
        config.setAlgorithm("PBEWithHmacSHA224AndAES_128");

        /*
            迭代计算次数,通过增加这个值可以提高加密效果的强度
         */
        config.setKeyObtentionIterations(1000); // 如果配置文件不做配置,则默认 1000 次

        config.setSaltGenerator(new RandomSaltGenerator()); // 具体的盐值生成器,未配置时默认使用 RandomSaltGenerator

        /*
            如果需要设置自定义的对称加密算法,那么这里可能需要设置成对应的算法提供对象,
            在一般情况下,系统提供的加密算法已经足够满足需求,因此可以设置为 null
         */
        config.setProvider(null);

        config.setStringOutputType("Base64"); // 处理时的字节表示形式

        config.setIvGenerator(new RandomIvGenerator()); // 某些算法可能需要使用到的初始向量生成器,默认为 RandomIvGenerator
        return config;
    }

    @Test
    public void encryptTest() {
        String message = "123"; // 当前需要被加密的密码

        final EnvironmentStringPBEConfig config = pbeConfig();

        final StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        encryptor.setConfig(config);

        log.info("{}", encryptor.encrypt(message)); // 这里得到的就是加密后的结果
    }
}

现在,将加密后的密码配置到我们系统的配置文件中,使用 jasypt 配置中定义的前后缀进行包装,以 Druid 配置为例,通过上文的加密算法,我将密码 "123" 加密后得到了 对应的加密文本 "354GiF5aGOgfrpisxVAw+y1fCNQ43Hv4vaHd9GVp8YZi86e0igV8sS6zyF1N14AP",现在将它配置到 Druid 的登录密码中:

spring:
  datasource:
    druid:
      stat-view-servlet:
        enabled: true
        login-username: admin
        login-password: ENC(354GiF5aGOgfrpisxVAw+y1fCNQ43Hv4vaHd9GVp8YZi86e0igV8sS6zyF1N14AP)

之后,如果希望登录 Druid 监视界面,只需要输入用户名为 admin 并且密码 123 即可完成登录

组件配置

一般情况下,Jasypt 默认的配置已经足够满足大部分的应用场景,然而,如果希望能够自定义相关的配置,Jasypt 也提供了相应的配置选项,主要包括 "过滤器"、"解码器" 以及 "检测器",这些组件在 com.ulisesbocchio.jasyptspringboot.properties.JasyptEncryptorConfigurationProperties.PropertyConfigurationProperties 有具体的描述

过滤器

过滤器的目的为了过滤那些需要进行解码的属性,默认情况下是对所有的配置属性都进行拦截处理,如果需要进行相关配置,可以在配置文件中加入相关的过滤属性字段:

jasypt:
  encryptor:
    property:
      filter:
      	# 需要传入全限定名称,以过滤这些不需要解密的字段
        exclude-names: ["spring.datasource.druid.stat-view-servlet.login-password"]

显然,如果需要过滤的字段太多,一个一个配置比较麻烦,因此我们可以自定顶一个过滤器来完成相关的过滤操作,具体的实现以 com.ulisesbocchio.jasyptspringboot.EncryptablePropertyFilter 定义的为准:

import com.ulisesbocchio.jasyptspringboot.EncryptablePropertyFilter;
import com.ulisesbocchio.jasyptspringboot.properties.JasyptEncryptorConfigurationProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

// 设置过滤器 Bean 名称,使得能够被加载到 Jasypt 的配置中
@Component("jasyptPropertiesFilter")
public class PropertiesFilter
        implements EncryptablePropertyFilter {

    private final Set<String> excludeSet = new HashSet<>();

    @Autowired
    public PropertiesFilter(ConfigurableEnvironment env) {
        // 复用 Jasypt 的过滤器配置属性
        JasyptEncryptorConfigurationProperties props = JasyptEncryptorConfigurationProperties.bindConfigProps(env);
        JasyptEncryptorConfigurationProperties.PropertyConfigurationProperties.FilterConfigurationProperties filterProps = props.getProperty().getFilter();
        excludeSet.addAll(filterProps.getExcludeNames());
    }

    @Override
    public boolean shouldInclude(PropertySource<?> source, String name) {
        // 如果是开发环境,则不需要对字段进行加密处理
        if (source.getName().endsWith("dev.yml")) {
            return true;
        }
        // 如果前缀与配置的匹配,则不进行加密处理
        for (String excludeName : excludeSet) {
            if (excludeName.startsWith(name)) {
                return false;
            }
        }
        return true;
    }
}

同时,需要将编写好的过滤器替换到原有的过滤器,可以通过配置如下属性来完成:

jasypt:
  encryptor:
    property:
      filter:
      	# 通过我们自定的过滤器,就不再需要写全限定名称了,只需要写对应的不匹配前缀即可
        exclude-names: ["spring.datasource.druid"]
      filter-bean: jasyptPropertiesFilter

检测器

检测器的目的是为了检查配置的属性是否是被加密的,效果与过滤器类似,区别在于过滤器的效果会先于检测器,默认的检测器实现是通过配置的前后缀值来进行判断的,即配置的 ENC()。如果希望改变这个行为(虽然基本不会改变

标签:加密,配置文件,Spring,springframework,import,org,config,com,public
From: https://www.cnblogs.com/FatalFlower/p/18288689

相关文章