springboot实现配置文件关键信息加解密

本文主要是介绍springboot实现配置文件关键信息加解密,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《springboot实现配置文件关键信息加解密》在项目配置文件中常常会配置如数据库连接信息,redis连接信息等,连接密码明文配置在配置文件中会很不安全,所以本文就来聊聊如何使用springboot...

前言

在项目配置文件中常常会配置如数据库连接信息、Redis连接信息,而连接密码明文配置在配置文件中会很不安全,所以就会将密码信息加密后放在配置文件中,在启动项目时自动解密转换成明文后进行连接,防止密码泄露。

方案

1、实现 EnvironmentPostProcessor 接口

2、引入 jasypt-spring-boot-starter 依赖

实践

1、第一种方案

EnvironmentPostProcessor 是 Spring Boot 提供的一个接口,用于在 Spring Boot 的 Environment 初始化完成后对其进行进一步的处理。它允许你在 Spring Boot 的配置加载阶段动态修改或增强 Environment 的内容,例如添加额外的配置源、修改属性值等。 ### 作用和用途

EnvironmentPostProcessor 的主要作用是在 Spring Boot 的启动过程中,对 Environment 对象进行扩展或修改。它通常用于以下场景:

  • 动态添加配置源:例如,从远程配置中心(如 Spring Cloud Config Server、Consul 等)加载配置。
  • 修改或覆盖配置属性:例如,根据环境变量或命令行参数动态调整某些配置值。
  • 解析加密的配置属性:例如,解密配置文件中加密的敏感信息。
  • 添加自定义的配置解析逻辑:例如,支持自定义的配置文件格式或解析规则。

使用方法

实现 EnvironmentPostProcessor 接口,并将自定义实现类注册到springboot中

import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import orgphp.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;

import Java.util.HashMap;
import java.util.Map;

/**
 * 自定义EnvironmentPostProcessor,在spring启动前将遍历配置文件中是否有加密的值,将加密的值按自定义解密工具进行解密
 */
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DecryptEnvironmentPostProcessor implements EnvironmentPostProcessor {

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        environment.getPropertySources().forEach(propertySource -> {
            if (propertySource instanceof MapPropertySource) {
                MapPropertySource mapSource = (MapPropertySource) propertySource;
                Map<String, Object> originalSource = mapSource.getSource();

     www.chinasem.cn           // 创建新的可修改 Map 副本
                Map<String, Object> decryptedSource = new HashMap<>(originalSource);

                // 遍历并解密值
                decryptedSource.replaceAll((key, value) -> {
                    if (value instanceof String) {
                        String strValue = (String) value;
                        if (strValue.startsWith("ENC(") && strValue.endsWith(")")) {
                            String encryptedContent = strValue.substring(4, strValue.length() - 1);
                            return AESEncryptionUtils.decrypt(encryptedContent);
                        }
                    }
                    return value;
                });

                // 用解密后的 Map 替换原 PropertySource
                environment.getPropertySources().replace(
                        mapSource.getName(),
                        new MapPropertySource(mapSource.getName(), decryptedSource)
                );
            }
        });
    }
}

注册 EnvironmentPostProcessor 实现类

META-INF/spring.factories 文件中注册你的 EnvironmentPostProcessor

org.springframework.boot.env.EnvironmentPostProcessor=\
  com.example.DecryptEnvironmentPostProcessor

自定义加解密工具类

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.security.SecureRandom;

public class AESEncryptionUtils {

    private static final String ALGORITHM = "AES/CBC/PKCS5Padding"; // 使用 CBC 模式 + PKCS5 填充
    private static final String SECRET_KEY = "oJ51lypwUNzBIFXO"; // 密钥环境变量名称

    /**
     * 加密明文
     * @param plaintext 待加密的明文
     * @return 格式为 "Base64(IV):Base64(密文)" 的字符串
     */
    public static String encrypt(String plaintext) {
        try {
            // 生成随机 IV
            byte[] ivbytes = new byte[16];
            SecureRandom random = new SecureRandom();
            random.nextBytes(ivBytes);
            IvParameterSpec iv = new IvParameterSpec(ivBytes);

            // 初始化加密器
            SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), "AES");
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);

            // 执行加密
            byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

            // 组合 IV 和密文,用 Base64 编码
            String iVBAse64 = Base64.getEncoder().encodeToString(ivBytes);
            String encryptedBase64 = Base64.getEncoder().encodeToString(encryptedBytes);
            return ivBase64 + ":" + encryptedBase64;
        } catch (Exception epython) {
            throw new RuntimeException("加密失败", e);
        }
    }

    /**
     * 解密密文
     * @param encryptedText 格式为 "Base64(IV):Base64(密文)" 的字符串
     * @return 解密后的明文
     */
    public static String decrypthttp://www.chinasem.cn(String encryptedText) {
        try {
            // 拆分 IV 和密文
            String[] parts = encryptedText.split(":");
            if (parts.length != 2) {
                throw new IllegalArgumentException("无效的加密格式");
            }
            byte[] ivBytes = Base64.getDecoder().decode(parts[0]);
            byte[] encryptedBytes = Base64.getDecoder().decode(parts[1]);

            // 初始化解密器
            IvParameterSpec iv = new IvParameterSpec(ivBytes);
            SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), "AES");
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, iChina编程v);

            // 执行解密
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("解密失败", e);
        }
    }
}

2、第二种方案

引入依赖

在项目的 pom.XML 文件中添加以下依赖:

<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.4</version>
</dependency>

配置 jasypt 信息

jasypt:
  encryptor:
    password: encryption-key
    algorithm: PBEWithMD5AndDES
    iv-generator-classname: org.jasypt.iv.NoIvGenerator

密码加密

从 Jasypt 官方网站 或 Maven 中央仓库下载 jasypt-1.9.3.jar

使用 Jasypt 的命令行工具对配置信息进行加密。例如,加密数据库密码:

java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="123456" password=encryption-key algorithm=PBEWithMD5AndDES

上述命令会输出一个加密后的字符串,例如:

springboot实现配置文件关键信息加解密

在配置文件中配置加密后的字符串:

spring:
  datasource:
    password: ENC(pxaWXichlG6mranljAUiZQ==)

应用启动时,jasypt 会使用密钥解密 ENC() 中的内容,并将其值注入到对应的配置属性中。

jasypt 加解密工具类

import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;

/**
 * jasypt 解密工具类
 */
public class EncryptionUtil {

    public static String encrypt(String input, String password) {
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        encryptor.setPassword(password);
        return encryptor.encrypt(input);
    }

    public static String decrypt(String encryptedValue, String password) {
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        encryptor.setPassword(password);
        return encryptor.decrypt(encryptedValue);
    }
}

补充

jasypt 密钥配置到配置文件中其实也不太安全,更安全的做法是将密钥配置到环境变量中或设置在启动命令中

export JASYPT_ENCRYPTOR_PASSWORD=your-encryption-key
java -jar your-application.jar --jasypt.encryptor.password=your-encryption-key

到此这篇关于springboot实现配置文件关键信息加解密的文章就介绍到这了,更多相关springboot配置文件信息加解密内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!

这篇关于springboot实现配置文件关键信息加解密的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1154527

相关文章

C#借助Spire.XLS for .NET实现在Excel中添加文档属性

《C#借助Spire.XLSfor.NET实现在Excel中添加文档属性》在日常的数据处理和项目管理中,Excel文档扮演着举足轻重的角色,本文将深入探讨如何在C#中借助强大的第三方库Spire.... 目录为什么需要程序化添加Excel文档属性使用Spire.XLS for .NET库实现文档属性管理Sp

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

Java方法重载与重写之同名方法的双面魔法(最新整理)

《Java方法重载与重写之同名方法的双面魔法(最新整理)》文章介绍了Java中的方法重载Overloading和方法重写Overriding的区别联系,方法重载是指在同一个类中,允许存在多个方法名相同... 目录Java方法重载与重写:同名方法的双面魔法方法重载(Overloading):同门师兄弟的不同绝

Spring配置扩展之JavaConfig的使用小结

《Spring配置扩展之JavaConfig的使用小结》JavaConfig是Spring框架中基于纯Java代码的配置方式,用于替代传统的XML配置,通过注解(如@Bean)定义Spring容器的组... 目录JavaConfig 的概念什么是JavaConfig?为什么使用 JavaConfig?Jav

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

Java中ArrayList与顺序表示例详解

《Java中ArrayList与顺序表示例详解》顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构,:本文主要介绍Java中ArrayList与... 目录前言一、Java集合框架核心接口与分类ArrayList二、顺序表数据结构中的顺序表三、常用代码手动

JAVA项目swing转javafx语法规则以及示例代码

《JAVA项目swing转javafx语法规则以及示例代码》:本文主要介绍JAVA项目swing转javafx语法规则以及示例代码的相关资料,文中详细讲解了主类继承、窗口创建、布局管理、控件替换、... 目录最常用的“一行换一行”速查表(直接全局替换)实际转换示例(JFramejs → JavaFX)迁移建

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

Python实现快速扫描目标主机的开放端口和服务

《Python实现快速扫描目标主机的开放端口和服务》这篇文章主要为大家详细介绍了如何使用Python编写一个功能强大的端口扫描器脚本,实现快速扫描目标主机的开放端口和服务,感兴趣的小伙伴可以了解下... 目录功能介绍场景应用1. 网络安全审计2. 系统管理维护3. 网络故障排查4. 合规性检查报错处理1.

JAVA线程的周期及调度机制详解

《JAVA线程的周期及调度机制详解》Java线程的生命周期包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED,线程调度依赖操作系统,采用抢占... 目录Java线程的生命周期线程状态转换示例代码JAVA线程调度机制优先级设置示例注意事项JAVA线程