SpringBoot 配置文件加密的步骤

SpringBoot 配置文件加密可以保护敏感的配置信息,比如数据库密码等,防止被恶意获取。下面是一些可能用到的步骤。

安装 JCE

JCE(Java Cryptography Extension)是Java加密扩展的缩写,如果你需要使用高强度加密算法,比如AES,那么需要下载安装对应的JCE版本。在Oracle官网下载后,将jar包解压到 $JAVA_HOME/jre/lib/security 目录下即可。

配置 application.properties

application.properties 中添加加密相关的配置,如下所示。

# 配置密钥,需要保证每个项目都不一样
encrypt.key=MY_ENCRYPT_KEY

# 配置需要加密的属性值
db.password=ENC(${cipher.db.password})

# 禁用 JMX
spring.jmx.enabled=false

其中,encrypt.key 是加密所使用的密钥,建议每个项目都使用不同的密钥;db.password 中的 ENC(${cipher.db.password}) 表示该值需要被加密,使用该格式添加需要加密的属性即可。

创建配置类

创建一个自定义的配置类,用于加密和解密。

import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.util.Arrays;

@Component
public class EncryptPropertyConfigurer {

    private static final String SHA_ALGORITHM = "SHA-256";
    private static final String ENCRYPTION_IV = "MY_ENCRYPTION_IV";

    @Value("${encrypt.key}")
    private String encryptKey;

    @Autowired
    private Environment environment;

    @PostConstruct
    public void init() {
        if (encryptKey == null || encryptKey.isEmpty()) {
            throw new IllegalArgumentException("encryptKey is empty");
        }
        if (ENCRYPTION_IV == null || ENCRYPTION_IV.isEmpty()) {
            throw new IllegalArgumentException("encryptionIV is empty");
        }
    }

    public String decrypt(String property) {
        if (!property.startsWith("ENC(") || !property.endsWith(")")) {
            throw new IllegalArgumentException("Invalid encrypted value: " + property);
        }
        property = property.substring(4, property.length() - 1);
        byte[] encryptedBytes = Base64.decodeBase64(property);
        try {
            SecretKeySpec secretKeySpec = getKeySpec();
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(ENCRYPTION_IV.getBytes("UTF-8")));
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
            return new String(decryptedBytes, "UTF-8");
        } catch (Exception e) {
            throw new RuntimeException("Error decrypting property", e);
        }
    }

    private SecretKeySpec getKeySpec() throws Exception {
        byte[] keyBytes = Arrays.copyOf(MessageDigest.getInstance(SHA_ALGORITHM).digest(encryptKey.getBytes("UTF-8")), 16);
        return new SecretKeySpec(keyBytes, "AES");
    }
}

该类使用 AES 算法进行加密和解密,encryptKey 为密钥,可以在 application.properties 设置,ENCRYPTION_IV 为初始向量。

示例1:加密单个属性

假设在 application.properties 文件中有以下属性:

db.password=root

可以将 db.password 进行加密,修改为:

db.password=ENC(ilOvI0UvbvRhIksj+GTw5g==)

其中,ilOvI0UvbvRhIksj+GTw5g== 是加密后的密码。

示例2:加密多个属性

示例1中只加密了一个属性,如果需要加密多个属性,可以使用下面的代码。

import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "cipher")
public class EncryptedPropertySource implements InitializingBean {

    private final EncryptPropertyConfigurer encryptPropertyConfigurer;

    public EncryptedPropertySource(EncryptPropertyConfigurer encryptPropertyConfigurer) {
        this.encryptPropertyConfigurer = encryptPropertyConfigurer;
    }

    private String dbPassword;
    private String secretKey;

    @Override
    public void afterPropertiesSet() {
        dbPassword = encryptPropertyConfigurer.decrypt(secretKey);
    }

    public String getDbPassword() {
        return dbPassword;
    }

    public void setDbPassword(String dbPassword) {
        this.dbPassword = dbPassword;
    }

    public String getSecretKey() {
        return secretKey;
    }

    public void setSecretKey(String secretKey) {
        this.secretKey = secretKey;
    }
}

该类使用 @ConfigurationProperties 注解读取加密后的属性,并使用 EncryptPropertyConfigurer 类解密。

以上是 SpringBoot 配置文件加密的一些步骤和示例,希望对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot 配置文件加密的步骤 - Python技术站

(0)
上一篇 2023年6月25日
下一篇 2023年6月25日

相关文章

  • Flex布局做出自适应页面(语法和案例)

    Flex布局做出自适应页面攻略 Flex布局是一种强大的CSS布局模型,可以帮助我们创建自适应页面。在本攻略中,我将详细介绍Flex布局的语法和提供两个示例说明。 语法 要使用Flex布局,我们需要在父容器上应用display: flex属性。这将把父容器转换为Flex容器,并启用Flex布局。 Flex容器属性 以下是一些常用的Flex容器属性: flex…

    other 2023年9月6日
    00
  • Android函数抽取壳的实现代码

    Android函数抽取壳的实现代码攻略 简介 抽取壳是一种技术手段,可用于保护Android应用程序的代码安全性。通过该技术,可以把关键函数和算法从原始的APK中提取出来,以减轻反编译和反向工程的风险。本文将详细介绍Android函数抽取壳的实现代码攻略。 实现步骤 步骤一:编写关键函数 首先,需要编写自己的关键函数,这些函数往往包含了应用程序的核心算法和逻…

    other 2023年6月28日
    00
  • sql无效字符 执行sql语句报错解决方案

    SQL无效字符执行SQL语句报错的解决方案 当我们在使用SQL语句时,有时候会碰到SQL无效字符的问题,导致SQL语句无法执行。这篇文章主要介绍如何解决SQL无效字符问题。 1. 什么是SQL无效字符 SQL语句中的无效字符是指不符合SQL语法规范的字符,包括但不限于以下几种情况: 关键字拼写错误; 语法错误; SQL注入攻击; 2. 解决方案 我们可以通过…

    other 2023年6月26日
    00
  • 基于arduino的wifi无线传输

    以下是关于“基于Arduino的WiFi无线传输”的完整攻略,包含两个示例说明。 基于Arduino的WiFi无线传输 在Arduino中,我们使用WiFi模块来实现无线传输。以下是一个基本的步骤: 连接WiFi模块到Arduino板上 在Arduino IDE中安装WiFi库。 编写代码来连接WiFi网络。 编写代码来发送和接收数据。 示例1:连接WiFi…

    other 2023年5月9日
    00
  • 机械师T90值得买吗?机械师T90悍狼游戏本深度评测+拆解

    很抱歉,作为文本模型,我无法以标准的markdown格式回答您的问题。但是,我可以为您提供一份详细的攻略,包含机械师T90悍狼游戏本的深度评测和拆解,并提供两个示例说明。 机械师T90悍狼游戏本深度评测+拆解 1. 外观设计 机械师T90悍狼游戏本采用了坚固耐用的金属外壳,具有独特的工业风格设计。其黑色外观和红色背光键盘给人一种高端大气的感觉。 2. 性能表…

    other 2023年10月17日
    00
  • Vue通过阿里云oss的url连接直接下载文件并修改文件名的方法

    以下是详细讲解”Vue通过阿里云oss的url连接直接下载文件并修改文件名的方法”的完整攻略: 阿里云oss相关准备 首先,需要在阿里云oss上创建一个bucket,并将需要下载的文件上传到该bucket中。然后,在权限管理中,将该bucket的跨域资源共享(CORS)配置添加如下代码,以允许其他域名的网站直接访问该bucket中的文件: [ { &quot…

    other 2023年6月26日
    00
  • PHP父类调用子类方法的代码例子

    首先,类的继承是面向对象编程中很重要的一个概念。PHP中,我们通过 extends 关键字来实现继承关系。假设下面有一段代码,它定义了一个基类 Animal 和它的子类 Dog,其中定义了基类的一个公共方法 run(): class Animal { public function run() { echo "Animal is running&q…

    other 2023年6月26日
    00
  • ExecutorService实现获取线程返回值

    获取线程返回值是很常见的需求,可以使用ExecutorService线程池来实现。下面是步骤: 步骤一:创建Callable Callable是一个带有返回值的线程接口,需要实现其中的call()方法来返回结果。例如,创建一个简单的Callable来计算两个数的和: import java.util.concurrent.Callable; public c…

    other 2023年6月26日
    00
合作推广
合作推广
分享本页
返回顶部