前言
在项目配置文件中常常会配置如数据库连接信息、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 org.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(); // 创建新的可修改 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 e) { throw new runtimeexception("加密失败", e); } } /** * 解密密文 * @param encryptedtext 格式为 "base64(iv):base64(密文)" 的字符串 * @return 解密后的明文 */ public static string decrypt(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, iv); // 执行解密 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
上述命令会输出一个加密后的字符串,例如:
在配置文件中配置加密后的字符串:
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配置文件信息加解密内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论