SpringBoot 整合Jasypt 实现配置文件加密读取操作详解

目录

一、前言

二、微服务中配置文件加密的常用方案

[2.1 对称加密](#2.1 对称加密)

[2.1.1 使用流程](#2.1.1 使用流程)

[2.1.2 优缺点](#2.1.2 优缺点)

[2.2 集成配置中心(Config Server)加解密](#2.2 集成配置中心(Config Server)加解密)

[2.2.1 工作原理](#2.2.1 工作原理)

[2.2.2 工作流程](#2.2.2 工作流程)

[2.2.3 优缺点](#2.2.3 优缺点)

[2.2.4 涉及到的常用工具](#2.2.4 涉及到的常用工具)

[2.3 使用专业的秘密管理服务](#2.3 使用专业的秘密管理服务)

[2.3.1 工作流程](#2.3.1 工作流程)

[2.3.2 优缺点](#2.3.2 优缺点)

[2.3.3 涉及到的常用工具](#2.3.3 涉及到的常用工具)

[2.4 Jasypt 介绍](#2.4 Jasypt 介绍)

[2.4.1 Jasypt 是什么](#2.4.1 Jasypt 是什么)

[2.4.2 Jasypt 核心特点](#2.4.2 Jasypt 核心特点)

[2.4.3 Jasypt 核心工作原理](#2.4.3 Jasypt 核心工作原理)

[2.4.4 Jasypt 优缺点](#2.4.4 Jasypt 优缺点)

[三、SpringBoot集成Jasypt 操作过程](#三、SpringBoot集成Jasypt 操作过程)

[3.1 前置准备](#3.1 前置准备)

[3.1.1 基础环境准备](#3.1.1 基础环境准备)

[3.1.2 pom文件添加依赖](#3.1.2 pom文件添加依赖)

[3.2 代码详细操作过程](#3.2 代码详细操作过程)

[3.2.1 前置配置文件信息](#3.2.1 前置配置文件信息)

[3.2.2 增加加解密工具类](#3.2.2 增加加解密工具类)

[3.2.3 修改配置文件](#3.2.3 修改配置文件)

[3.2.4 效果验证](#3.2.4 效果验证)

[3.3 安全加密升级操作](#3.3 安全加密升级操作)

[3.3.1 自定义加密配置类](#3.3.1 自定义加密配置类)

[3.3.2 调整配置文件](#3.3.2 调整配置文件)

[3.3.3 效果验证](#3.3.3 效果验证)

四、写在文末


一、前言

在很多微服务项目中,配置文件中存放了mysql等数据库密码、redis密码以及一些中间件的连接信息,甚至还有一些与三方平台对接的账户密码等。很多情况下,配置文件中的密码等敏感信息都是以明文形式存在。这种配置本身没有问题,但在某些情况下,一旦这些敏感信息泄漏,可能会对公司造成不可挽救的损失,比如:某一天,小王不小心把公司项目上传到自己GitHub仓库里,后果就是,公司数据库用户名密码泄露,加上这些连接信息是公网就可以访问的,这样造成的后果将会非常严重。

二、微服务中配置文件加密的常用方案

在实际的微服务开发中,有很多解决方案可用于解决读取配置文件数据的安全传输问题,比较通用的一种思路就是对配置文件中的敏感信息进行加密处理,读取的时候再解密,下面介绍几种常用的解决方案。

2.1 对称加密

对称加密是最基础和直接的方式。它的主要原理是使用同一个密钥(Secret Key)进行加密和解密。在配置中心或CI/CD流程中加密配置值,微服务启动时用相同的密钥解密。对称加密的常用算法为:AES(Advanced Encryption Standard)。

2.1.1 使用流程

具体来说,使用这种方式需要经过3步:

  1. 加密

  2. 密文存储

  3. 解密

1)加密

比如通过下面的命令行即可实现敏感数据的加密

  • 一般通过命令行工具(如 openssl)或脚本在部署前加密敏感值
bash 复制代码
# 示例:使用 openssl 加密一个字符串
echo "my_super_secret_db_password" | openssl enc -aes-256-cbc -md sha512 -a -pbkdf2 -iter 100000 -salt -pass pass:${MASTER_KEY}

2)密文存储

将加密后的密文(ciphertext)存入配置文件,通常会用特殊标识符包裹,如 {cipher}FKSAJdFAIJDS...

3)解密

微服务应用在启动时读取到加密值,通过预置的密钥(作为环境变量或启动参数传入)在内存中解密并使用。

2.1.2 优缺点

  • 优点:

    • 实现简单,易于理解和实施。

    • 计算开销小,性能好。

  • 缺点:

    • 密钥分发问题:加解密密钥(MASTER_KEY)本身需要安全地分发给每一个微服务实例,这成了新的安全问题。通常需要通过环境变量、云平台的秘密管理器或启动脚本注入,要确保其安全。

    • 密钥轮换困难。

2.2 集成配置中心(Config Server)加解密

这是Spring Cloud等生态体系中最主流和推荐的方式。

2.2.1 工作原理

配置中心在很多微服务项目中可以说是标配,比如nacos,appolo等,配置中心主要是充当配置管理的中间层,它提供统一的加解密端点。配置文件的加密和解密工作由配置中心负责,微服务客户端从配置中心获取的是解密后的明文(通过安全的HTTPS通道)。

2.2.2 工作流程

集成配置中心的加解密功能,其核心实现流程如下:

  1. 加密:开发人员通过配置中心提供的 /encrypt HTTP端点加密敏感信息。

  2. 存储:将加密后的密文存入Git等配置仓库中。配置文件里存储的是 {cipher}密文

  3. 解密:微服务向配置中心请求配置。

  4. 响应:配置中心从Git仓库读取到加密的配置值,调用其内部的解密器进行解密,然后将明文配置通过HTTPS返回给微服务客户端。

2.2.3 优缺点

这种方式主要有下面的优缺点:

  • 优点:

    • 解耦:微服务应用本身无需关心解密逻辑和密钥管理,只需连接配置中心。

    • 集中管理:密钥管理集中在配置中心服务器上,安全性更高。

    • 与Git集成:配置仍然可以用Git进行版本管理,但存储的是密文。

  • 缺点:

    • 需要额外部署和维护一个高可用的配置中心。

    • 配置中心本身成为关键单点,需要重点保护。

2.2.4 涉及到的常用工具

  • Spring Cloud Config Server:支持对称加密(AES)和非对称加密(RSA)。

  • HashiCorp Vault:更专业的秘密管理工具,可以直接作为配置中心,也常与Spring Cloud Config集成,作为其后端。

2.3 使用专业的秘密管理服务

这是在现代云原生环境(Kubernetes, Docker Swarm)中最云原生(Cloud-Native)的方式。

这种方式完全摒弃在配置文件中存储敏感信息的做法,转而使用专门为管理秘密而设计的服务。应用程序通过API或Sidecar容器从这些服务中动态获取秘密。

2.3.1 工作流程

具体来说,这种方式的工作流程如下:

  1. 将所有的敏感信息(密码、令牌、证书)存入秘密管理服务。

  2. 微服务在启动时或运行时,通过其提供的客户端库或API(通常需要身份认证)来拉取所需的秘密。

  3. 秘密通常被注入到环境变量或内存文件系统(如K8s的Secret对象挂载为Volume)中,供应用读取。

2.3.2 优缺点

这种方式的优缺点如下:

  • 优点:

    • 最高安全性:秘密永不落地(不在配置文件、镜像、代码中),全程加密存储和传输。

    • 动态秘密:可以生成动态的、有生命周期的秘密(如数据库临时密码),极大增强安全性。

    • 详细的审计日志:可以记录谁在何时访问了哪个秘密。

    • 完善的权限控制和租户隔离。

  • 缺点:

    • 架构复杂,需要引入新的组件和服务。

    • 应用程序需要集成对应的客户端或修改代码来获取秘密。

2.3.3 涉及到的常用工具

  • HashiCorp Vault:行业标准,功能极其强大,支持动态秘密、加密即服务等。

  • AWS Secrets Manager / AWS Parameter Store:深度集成于AWS生态。

  • Azure Key Vault:Azure云的首选方案。

  • Google Cloud Secret Manager:GCP平台的选择。

  • Kubernetes Secrets:K8s原生的秘密对象,虽然基础(默认Base64编码,非加密),但可以集成上述专业工具或配合第三方加密工具(如Sealed Secrets, External Secrets Operator)使用。

2.4 Jasypt 介绍

2.4.1 Jasypt 是什么

Jasypt,全称 Java Simplify Encryption,是一个用于 Java 应用程序的、简单而强大的加密库。它主要致力于让开发者能够以最小的努力为项目添加基本的加密功能,特别是针对配置文件(如 Spring Boot 的 application.properties/application.yml)中的敏感信息加密。

Jasypt 的核心目标是:"加密,然后配置"。即先对敏感信息进行加密,然后将密文配置到文件中,应用程序在运行时再对其进行解密。

2.4.2 Jasypt 核心特点

Jasypt 具备如下核心特点:

  1. 简单易用:API 设计得非常简洁,几行代码即可完成加解密。同时提供与 Spring Framework、Spring Boot 的无缝集成。

  2. 功能丰富:支持多种加密算法,包括:

    1. PBE(Password-Based Encryption):这是 Jasypt 最常用和推荐的方式,例如 PBEWithMD5AndDESPBEWithHMACSHA512AndAES_256 等。它通过一个密码(Password)和盐(Salt)来派生密钥进行加解密,安全性很高。

    2. 摘要加密(Digest):如 MD5, SHA-1, SHA-256 等(通常用于哈希,而非可解密加密)。

  3. 配置集成:这是其最受欢迎的特性。它可以轻松集成到 Spring 和 Spring Boot 中,直接解密配置文件中的 {cipher}... 密文,对应用程序代码几乎无侵入。

  4. 多用途:不仅可以加密字符串,还可以加密二进制数据(如图片、文件)。

  5. 线程安全:其加密器是线程安全的,可以在多线程环境中共享使用。

2.4.3 Jasypt 核心工作原理

Jasypt 在使用过程中主要分解密过程和解密过程,具体来说,如下步骤。

1)加密阶段

  • 你拥有一个明文敏感信息,比如数据库密码 mysecretpassword

  • 选择一个加密算法和一个主密码(Master Password)。

  • 使用 Jasypt 的 API 或命令行工具对明文进行加密,得到密文,例如 ENC(abcd1234xyz5678...)

  • 用密文替换配置文件中的明文。

下面是一段经常能在工程的配置文件中看到的配置信息

bash 复制代码
# 加密前
spring.datasource.password=root@123456

# 加密后
spring.datasource.password=ENC(abcd1234xyz5678...)

2)解密阶段

即程序在运行过程中的时候,将会按照下面的流程进行:

  • 应用程序启动并读取配置文件。

  • Jasypt 的集成组件(如 PropertySourcePlaceholderConfigurerSpring Boot Starter)会检测到以 ENC(...) 包裹的密文。

  • 组件使用你提供的主密码(Master Password)对密文进行解密,还原出原始的明文 mysecretpassword

  • 应用程序拿到的是解密后的明文,并正常使用它来创建数据源等组件。整个过程在内存中进行,明文不会暴露在磁盘上。

2.4.4 Jasypt 优缺点

总结来说,Jasypt具有如下优缺点:

优点:

  • 极大降低入门门槛:API 和配置都非常简单,几分钟就能让配置加密跑起来。

  • 对代码低侵入:尤其是在 Spring 项目中,业务代码完全感知不到加密解密的逻辑。

  • 社区活跃:是 Java 生态中知名度最高、使用最广泛的配置加密库之一。

缺点:

  • 密钥管理仍需自行解决:Jasypt 本身只负责加解密,最核心的主密码(Master Password)如何安全地传递给应用程序,这个难题留给了开发者。你需要通过环境变量、启动参数、文件等方式来管理它。

  • 并非银弹:它的安全性建立在主密码的保密性上。如果攻击者拿到了主密码和配置文件,他们就能解密所有信息。对于更高安全要求的场景,应使用 HashiCorp Vault 或云厂商的秘密管理服务,这些服务提供了更完善的认证、授权、审计和动态秘密功能。

总结

Jasypt 是一个优秀的、轻量级的配置加密入门解决方案。它非常适合中小型项目、初创公司或者希望快速为现有 Spring/Spring Boot 应用增加配置安全性的团队。

但对于大型、对安全有极高要求的云原生应用,建议将 Jasypt 视为一个过渡方案,并长远规划迁移到更专业的秘密管理服务(如 Vault)上。

三、SpringBoot集成Jasypt 操作过程

接下来通过实际案例操作演示下如何在SpringBoot项目中集成Jasypt 。

3.1 前置准备

3.1.1 基础环境准备

数据库环境

  • 程序运行中需要操作数据库,提前准备好mysql数据库

技术栈

  • springboot(3.3) + jdk17 + mybatis-plus + Jasypt

提前搭建一个springboot工程

3.1.2 pom文件添加依赖

在工程的pom文件中添加下面的核心依赖

bash 复制代码
<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.3</version>
    <relativePath/>
</parent>

<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Mysql Connector -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
    </dependency>

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>3.0.3</version>
    </dependency>

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.5</version>
        <exclusions>
            <exclusion>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

    <dependency>
        <groupId>com.github.ulisesbocchio</groupId>
        <artifactId>jasypt-spring-boot-starter</artifactId>
        <version>3.0.5</version> <!-- 建议使用最新版本 -->
    </dependency>

</dependencies>

<build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

3.2 代码详细操作过程

3.2.1 前置配置文件信息

如下,在我们的工程配置文件中,在配置连接数据库的时候,一般会配置下面的连接信息,通常数据库连接的用户名和密码为明文,后面将会使用jasypt进行改造

3.2.2 增加加解密工具类

增加一个用于加解密的工具类,参考下面的代码

java 复制代码
package com.congge.utils;

import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.EnvironmentPBEConfig;

public class JasyptUtil {

    /**
     * PBE 算法,下面提供了多种类型的算法,实际使用中可以根据自己的需求进行选择
     */
    public static final String PBE_ALGORITHMS_MD5_DES = "PBEWITHMD5ANDDES";
    public static final String PBE_ALGORITHMS_MD5_TRIPLEDES = "PBEWITHMD5ANDTRIPLEDES";
    public static final String PBE_ALGORITHMS_SHA1_DESEDE = "PBEWITHSHA1ANDDESEDE";
    public static final String PBE_ALGORITHMS_SHA1_RC2_40 = "PBEWITHSHA1ANDRC2_40";

    public static final String PBEWITHHMACSHA512ANDAES_256 = "PBEWITHHMACSHA512ANDAES_256";

    private JasyptUtil() {
    }

    /**
     * Jasypt 加密
     *
     * @param encryptedStr 加密字符串
     * @param salt     盐值
     * @return
     */
    public static String encrypt(String encryptedStr, String salt) {
        return encrypt(encryptedStr, PBE_ALGORITHMS_MD5_DES, salt);
    }

    /**
     * Jasypt 加密
     *
     * @param encryptedStr 加密字符串
     * @param algorithm    加密算法
     *                     PBE ALGORITHMS: [PBEWITHMD5ANDDES, PBEWITHMD5ANDTRIPLEDES, PBEWITHSHA1ANDDESEDE, PBEWITHSHA1ANDRC2_40]
     * @param salt     盐值
     * @return
     */
    public static String encrypt(String encryptedStr, String algorithm, String salt) {
        // StandardPBEStringEncryptor、StandardPBEBigDecimalEncryptor、StandardPBEBigIntegerEncryptor、StandardPBEByteEncryptor
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        EnvironmentPBEConfig config = new EnvironmentPBEConfig();

        // 指定加密算法
        config.setAlgorithm(algorithm);
        // 加密盐值
        config.setPassword(salt);
        //config.setIvGeneratorClassName("org.jasypt.iv.NoIvGenerator");
        encryptor.setConfig(config);

        // 加密
        return encryptor.encrypt(encryptedStr);
    }

    /**
     * Jasypt 解密
     *
     * @param decryptStr 解密字符串
     * @param salt   盐值
     * @return
     */
    public static String decrypt(String decryptStr, String salt) {
        return decrypt(decryptStr, PBE_ALGORITHMS_MD5_DES, salt);
    }

    /**
     * Jasypt 解密
     *
     * @param decryptStr 解密字符串
     * @param algorithm  指定解密算法:解密算法要与加密算法一一对应
     *                   PBE ALGORITHMS: [PBEWITHMD5ANDDES, PBEWITHMD5ANDTRIPLEDES, PBEWITHSHA1ANDDESEDE, PBEWITHSHA1ANDRC2_40]
     * @param salt   盐值
     * @return
     */
    public static String decrypt(String decryptStr, String algorithm, String salt) {
        // StandardPBEStringEncryptor、StandardPBEBigDecimalEncryptor、StandardPBEBigIntegerEncryptor、StandardPBEByteEncryptor
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        EnvironmentPBEConfig config = new EnvironmentPBEConfig();
        // 指定解密算法:解密算法要与加密算法一一对应
        config.setAlgorithm(algorithm);
        // 加密秘钥
        config.setPassword(salt);
        //config.setIvGeneratorClassName("org.jasypt.iv.NoIvGenerator");
        encryptor.setConfig(config);
        // 解密
        return encryptor.decrypt(decryptStr);
    }

    public static void main(String[] args) {
        //需要加密的明文字符串
        String encryptedStr = "root";
        //使用的加密算法
        String algorithm = PBE_ALGORITHMS_SHA1_RC2_40;
        //密钥
        String password = "db-salt";
        String str = JasyptUtil.encrypt(encryptedStr, algorithm, password);
        System.out.println("加密后的字符串:" + str);
        System.out.println("解密后的字符串:" + JasyptUtil.decrypt(str, algorithm, password));
    }
}

在main方法中,调用工具类中的方法,分别对上一步配置文件中的数据库账户名和密码进行加密:

  • 调用2次之后,得到账户和密码的加密串,请记住这两个加密串,待会需要拷贝到配置文件中

  • 记住程序中的密钥,这个密钥是后续密文解密的关键

  • 每次加密的后得到的密文可能不一样,只要密钥是同一个,即可正常进行解密

3.2.3 修改配置文件

调整工程的配置文件,如下:

java 复制代码
server:
  port: 8082

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://数据库连接IP:3306/user_db
    username: ENC(WUpmP7f1jPdSKjhiAR88Wg==)
    password: ENC(pKUy3QAnezymd/0EeoRCON9HdqYahxWc)

# =================== 配置参数加密相关的信息 ===================
jasypt:
  encryptor:
    password: db-salt
    algorithm: PBEWITHSHA1ANDRC2_40
    iv-generator-classname: org.jasypt.iv.NoIvGenerator
# =================== 配置参数加密相关的信息 ===================

mybatis-plus:
  # 不支持多包, 如有需要可在注解配置 或 提升扫包等级
  # 例如 com.**.**.mapper
  mapperPackage: com.congge.mapper
  # 对应的 XML 文件位置
  mapperLocations: classpath*:mapper/**/*Mapper.xml
  # 实体扫描,多个package用逗号或者分号分隔
  typeAliasesPackage: com.congge.entity
  global-config:
    dbConfig:
      # 主键类型
      # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
      # 如需改为自增 需要将数据库表全部设置为自增
      idType: ASSIGN_ID
      # 逻辑已删除值(默认为 1)
      logic-delete-value: 1
      # 逻辑未删除值(默认为 0)
      logic-not-delete-value: 0

3.2.4 效果验证

通过上面的配置之后,就基本完成了配置文件的加密操作了,启动工程后,只要是对于数据库的操作能够正常完成,配置就成功了,下面通过工程中的一个接口进行验证,调用接口,数据库的数据仍然可以正常查询即可。

3.3 安全加密升级操作

在上面的操作中,使用的是默认的加密配置规则,细心的同学会发现,密钥我们是写在工程的配置文件中的,一定程度上,可能也会成为不安全的因素。为了进一步防止密码泄露,我们可以自定义加密规则。下面看具体的操作步骤。

3.3.1 自定义加密配置类

在当前的工程中,增加一个自定义的加密配置类,参考下面的代码

  • 注意程序里的密钥仍然和上面那个保持一致
java 复制代码
package com.congge.utils;

import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JasyptConfig {

    /**
     * 加密的密钥
     */
    private static final String SALT = "db-salt";

    /**
     * 加密算法,还有很多可以选择,这里使用PBEWITHSHA1ANDRC2_40
     */
    private static final String ALGORITHM = "PBEWITHSHA1ANDRC2_40";

    @Bean(name = "jasyptStringEncryptor")
    public StringEncryptor stringEncryptor() {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        // 设置加密密钥
        config.setPassword(SALT);
        // 配置加密算法
        config.setAlgorithm(ALGORITHM);
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setIvGeneratorClassName("org.jasypt.iv.NoIvGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
        return encryptor;
    }
}

3.3.2 调整配置文件

配置文件中涉及到加密的配置部分需要调整,其他的保持不变,参考下面的配置信息

  • 可以看到,这里是将自定义的bean的名称配置进去,而不需要将密钥配置进去
java 复制代码
jasypt:
  encryptor:
#    password: db-salt
#    algorithm: PBEWITHSHA1ANDRC2_40
#    iv-generator-classname: org.jasypt.iv.NoIvGenerator
    
    #使用自定义配置bean的方式集成,安全性更好,暴露的参数更少
    bean: jasyptStringEncryptor
    property:
      prefix: ENC(
      suffix: )

3.3.3 效果验证

配置完成后,再次启动工程,再次调用同样的接口进行效果验证,仍然可以得到相同的结果

四、写在文末

本文通过案例操作详细介绍了java中对配置文件读取进行加密操作的jasypt这种技术组件的使用,更深入的有兴趣的同学可以基于此继续深入研究,本篇到此结束,感谢观看。