SpringBoot配置文件数据加密自定义开发详解

本文介绍了如何使用RSA加密算法对SpringBoot的配置文件进行加密,以增强安全性。通过生成公钥和私钥,对敏感信息进行加密,并在应用运行时使用BeanFactoryPostProcessor接口解密。提供了公钥私钥的配置方法,包括通过配置文件和命令行参数传递。测试结果显示解密成功,密码恢复为原始值。
摘要由CSDN通过智能技术生成

SpringBoot 配置文件加密

本章将对SpringBoot配置文件中的数据加密做自定义开发. 在SpringBoot开发过程中配置文件是明文存放在application.yml或者application.properties文件中,这种配置方式会带来一定的安全隐患,本章将对这个问题提出一个简单的解决方案。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

编码

首先需要确定一个加密解密方式,本文采用RSA进行加密解密,首先编写加密解密的代码,注意RSA加密解密需要使用到公钥和私钥,公钥私钥的生成代码如下:

 
 

public static void generateKey() throws NoSuchAlgorithmException { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(EncryptionType.RSA); keyPairGen.initialize(1024, new SecureRandom()); KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到私钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 得到公钥 String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded())); String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded()))); System.out.println("当前生成的公钥= " + publicKeyString); System.out.println("当前生成的私钥= " + privateKeyString); }

加密代码如下:

 
 

public static String encrypt(String str, String publicKey) throws NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException { byte[] decoded = Base64.decodeBase64(publicKey); RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance(EncryptionType.RSA).generatePublic(new X509EncodedKeySpec(decoded)); Cipher cipher = Cipher.getInstance(EncryptionType.RSA); cipher.init(Cipher.ENCRYPT_MODE, pubKey); return Base64.encodeBase64String(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8))); }

解密代码如下:

 
 

public static String decrypt(String str, String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException { byte[] inputByte = Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8)); byte[] decoded = Base64.decodeBase64(privateKey); RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(EncryptionType.RSA).generatePrivate(new PKCS8EncodedKeySpec(decoded)); Cipher cipher = Cipher.getInstance(EncryptionType.RSA); cipher.init(Cipher.DECRYPT_MODE, priKey); return new String(cipher.doFinal(inputByte)); }

上述代码为基本的加密解密工具,加下来需要在配置文件中确定哪些配置是需要进行解密的,本例将采用自定义前缀+后缀的方式进行匹配,前缀为PWD[,后缀为],如果在配置文件中属性值是以前缀后缀包裹的那么这个数据会被进行解密操作,

通过前文的加密工具可以先进行一次密码加密加密原文为1234qwer,公钥:

 
 

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCBOkkkvjbOQ6UTCo8U4bRC/EcEtxz8haHg6lueM3NBbH3eIT7kfwQFOqj1h1qPGcQNeyn4vxzMWBAKzSQehjqVBL7/8GN7EZ7TEaUuWO+8qsuZnOdrztX7bNKACnks+SelmtbrbnFKUMAq2c2mS0o1V6iwyRxJYLGaHGXnz4KSkwIDAQAB

私钥:

 
 

MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIE6SSS+Ns5DpRMKjxThtEL8RwS3HPyFoeDqW54zc0Fsfd4hPuR/BAU6qPWHWo8ZxA17Kfi/HMxYEArNJB6GOpUEvv/wY3sRntMRpS5Y77yqy5mc52vO1fts0oAKeSz5J6Wa1utucUpQwCrZzaZLSjVXqLDJHElgsZocZefPgpKTAgMBAAECgYAFaCDjTqoQWzgu4cQ2xXK7Ur7N7bNixVyOgn+u0MxDsnxZrN5qxP2wElI7Y5xgXF2diseoxqY3zn9tVEPsmwUcY73naoosx9V8oExgT/BUkZYIzj1ei08zOr984zl3dbFcxOCRvqywXj9FAAGx1mhmCzFCIauJg3aX0S9mt5/CwQJBAMYZsmMQ9owoXZuSclKVRfMHFpAPhQlcBM4xadhX0IRYATgNTxpESmcCoGWvyw3bvieNJyC9Njx6X4FJ2EZUzhECQQCm/2IM5MlsCwyKtME5RPFna2hSqYU80UzkNfDIyMokcU2JUI4Fhigog4ol0GFMiMBsHIjS+cJiAwNbIsq5rsJjAkA94yVBobkETFACHBwvBIdXxy0bUF3lcKPnrrQ8bCKuVbf7xNyjfhYoXD+zxNmQuMeNH6HLrpDVD/3qLCGuxyuhAkAiLPl/8gJWnhw+9qbkdXuB0rVS1WZy/9JgkblpHc5gjt9zTo0CDGaDhAftnSuMYiAe/+fwZTSmoj85k3ExdtZJAkEArJuG/NWY9HP4p7jtZX9rMokyB3517v7HQdJKBDIlOzseRC/roCvU8LQ/URDFBUqXCRgedxgW+0ZmKFf4xeawqw==

加密结果为:

 
 

PWD[bMw8oqC/ma31JqF0DCuf5QWqSFRMigYw3fMBIIIfJ85vnmNnFbH9IcJfUHgbSmNHeITffToODwAygy4vKdzu6o1i1UQOd8w4nPKhnVJCLKqW5jmc3Yw+FkTIRBp63NJWzECVnRHqEK+bTxPMa1gfKql/2U45XxqeDSZOEXGeA+E=]

得到这个数据后将其配置在application.properties文件中,具体内容如下

 
 

server.port=8080 spring.application.name=test-app spring.datasource.password=PWD[bMw8oqC/ma31JqF0DCuf5QWqSFRMigYw3fMBIIIfJ85vnmNnFbH9IcJfUHgbSmNHeITffToODwAygy4vKdzu6o1i1UQOd8w4nPKhnVJCLKqW5jmc3Yw+FkTIRBp63NJWzECVnRHqEK+bTxPMa1gfKql/2U45XxqeDSZOEXGeA+E=]

接下来需要进一步解决的是如何将这个加密字符串进行解密,这里需要使用BeanFactoryPostProcessor接口对环境变量进行修改,具体实现代码如下:

 
 

@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { MutablePropertySources propertySources = environment.getPropertySources(); for (PropertySource<?> propertySource : propertySources) { if (propertySource instanceof OriginTrackedMapPropertySource ) { OriginTrackedMapPropertySource om = (OriginTrackedMapPropertySource) propertySource; Map<String, Object> source = om.getSource(); source.forEach((k, v) -> { String property = environment.getProperty(k); if (hasPreAndSuf(property)) { LOG.info("开始处理 k = [{}]", k); try { String relay = splitPreAndSuf(property, this.prefix, this.suffix); String decrypt = RSAEncrypt.decrypt(relay, getPrivateKey(environment)); source.put(k, decrypt); } catch (Exception e) { LOG.error("e = ", e); } } }); } } }

处理逻辑如下:

  1. 提取环境配置中的所有配置属性

  2. 判断配置属性是否是OriginTrackedMapPropertySource类型,该类型的数据是在application.yaml中的内容

  3. 处理OriginTrackedMapPropertySource对象的value值,如果value包含自定义前缀后缀则进行解密

在本例中对于公钥私钥以及前缀后缀是允许自定义的,开发者只需要在配置文件中根据下面表格进行填写即可

属性名称

属性含义

默认值

encryption.prefix

前缀

PWD[

encryption.suffix

后缀

]

encryption.rsa.publicKey

公钥

encryption.rsa.privateKey

私钥

注意:**为了便捷操作开放了配置文件形式的公钥秘钥的配置,这部分配置可以在测试环境中开发环境中进行使用。**如果需要在生产环境中使用请使用下面两种方式:

方式一:在项目资源目录resources文件夹下创建hf_private_key文件,向文件中填写如下内容

 
 

encryption.rsa.privateKey=MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIE6SSS+Ns5DpRMKjxThtEL8RwS3HPyFoeDqW54zc0Fsfd4hPuR/BAU6qPWHWo8ZxA17Kfi/HMxYEArNJB6GOpUEvv/wY3sRntMRpS5Y77yqy5mc52vO1fts0oAKeSz5J6Wa1utucUpQwCrZzaZLSjVXqLDJHElgsZocZefPgpKTAgMBAAECgYAFaCDjTqoQWzgu4cQ2xXK7Ur7N7bNixVyOgn+u0MxDsnxZrN5qxP2wElI7Y5xgXF2diseoxqY3zn9tVEPsmwUcY73naoosx9V8oExgT/BUkZYIzj1ei08zOr984zl3dbFcxOCRvqywXj9FAAGx1mhmCzFCIauJg3aX0S9mt5/CwQJBAMYZsmMQ9owoXZuSclKVRfMHFpAPhQlcBM4xadhX0IRYATgNTxpESmcCoGWvyw3bvieNJyC9Njx6X4FJ2EZUzhECQQCm/2IM5MlsCwyKtME5RPFna2hSqYU80UzkNfDIyMokcU2JUI4Fhigog4ol0GFMiMBsHIjS+cJiAwNbIsq5rsJjAkA94yVBobkETFACHBwvBIdXxy0bUF3lcKPnrrQ8bCKuVbf7xNyjfhYoXD+zxNmQuMeNH6HLrpDVD/3qLCGuxyuhAkAiLPl/8gJWnhw+9qbkdXuB0rVS1WZy/9JgkblpHc5gjt9zTo0CDGaDhAftnSuMYiAe/+fwZTSmoj85k3ExdtZJAkEArJuG/NWY9HP4p7jtZX9rMokyB3517v7HQdJKBDIlOzseRC/roCvU8LQ/URDFBUqXCRgedxgW+0ZmKFf4xeawqw==

需要将等于号后面的内容进行修改,替换为项目中的秘钥

方式二:通过命令行进行传递

在启动命令中添加

 
 

-Dencryption.rsa.privateKey=MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIE6SSS+Ns5DpRMKjxThtEL8RwS3HPyFoeDqW54zc0Fsfd4hPuR/BAU6qPWHWo8ZxA17Kfi/HMxYEArNJB6GOpUEvv/wY3sRntMRpS5Y77yqy5mc52vO1fts0oAKeSz5J6Wa1utucUpQwCrZzaZLSjVXqLDJHElgsZocZefPgpKTAgMBAAECgYAFaCDjTqoQWzgu4cQ2xXK7Ur7N7bNixVyOgn+u0MxDsnxZrN5qxP2wElI7Y5xgXF2diseoxqY3zn9tVEPsmwUcY73naoosx9V8oExgT/BUkZYIzj1ei08zOr984zl3dbFcxOCRvqywXj9FAAGx1mhmCzFCIauJg3aX0S9mt5/CwQJBAMYZsmMQ9owoXZuSclKVRfMHFpAPhQlcBM4xadhX0IRYATgNTxpESmcCoGWvyw3bvieNJyC9Njx6X4FJ2EZUzhECQQCm/2IM5MlsCwyKtME5RPFna2hSqYU80UzkNfDIyMokcU2JUI4Fhigog4ol0GFMiMBsHIjS+cJiAwNbIsq5rsJjAkA94yVBobkETFACHBwvBIdXxy0bUF3lcKPnrrQ8bCKuVbf7xNyjfhYoXD+zxNmQuMeNH6HLrpDVD/3qLCGuxyuhAkAiLPl/8gJWnhw+9qbkdXuB0rVS1WZy/9JgkblpHc5gjt9zTo0CDGaDhAftnSuMYiAe/+fwZTSmoj85k3ExdtZJAkEArJuG/NWY9HP4p7jtZX9rMokyB3517v7HQdJKBDIlOzseRC/roCvU8LQ/URDFBUqXCRgedxgW+0ZmKFf4xeawqw==

需要将等号后面的内容进行修改,替换为项目中的秘钥

从笔者所经历的角度来看命令行传递参数可能更加安全一些,因为文件和命令行相比命令行需要在生产环境才可以看到,而文件在仓库中会存在。

接下来做一个测试,在启动时输出spring.datasource.password属性查看是否是加密前的数据,测试代码如下:

 
 

@SpringBootApplication public class App { @Value("${spring.datasource.password}") private String dataSourceProperties; public static void main(String[] args) { SpringApplication.run(App.class, args); } @Bean public ApplicationRunner runner() { return args -> { System.out.println(dataSourceProperties); }; } }

启动项目后可以看到控制台输出

 
 

1234qwer

                                      资源获取:
大家 点赞、收藏、关注、评论啦 、 查看👇🏻👇🏻👇🏻 微信公众号获取联系方式👇🏻👇🏻👇🏻
精彩专栏推荐订阅:下方专栏👇🏻👇🏻👇🏻👇🏻
每天学四小时:Java+Spring+JVM+分布式高并发,架构师指日可待

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值