简介
软件系统不可避免地需要将一些关键信息存储在配置文件中,这包括但不限于数据库的密码、Redis缓存的密码等敏感数据。在开发测试环境中,出于方便与效率的考虑,我们或许可以接受这些敏感信息以明文形式存在。然而,一旦进入生产环境,这样的明文配置方式将带来极大的安全隐患,因为它使得任何能够访问这些配置文件的人都有可能获取到这些敏感信息,进而可能对公司的数据安全造成严重的威胁。
除了敏感信息外,即使是次敏感信息,如数据库的连接地址和账号,我们也希望进行隐藏处理,以进一步提高系统的安全性。为此,我们需要找到一种既能保护信息安全,又能方便使用的方法。
解决这个问题的一个有效思路就是使用对称加密算法。在配置时,我们可以将这些敏感和次敏感信息进行加密处理,然后在需要使用时再进行解密。虽然自己编写加密解密程序在技术上并不困难,但这需要投入一定的时间和精力,而且容易因为一些细节问题而引入隐含的bug,甚至可能影响到系统的性能。
因此,为了更高效地解决这个问题,我们可以选择使用现有的成熟的工具包,比如jasypt。
jasypt是一个强大的加密库,它提供了简单易用的接口,使得我们可以在SpringBoot项目中非常方便地实现敏感信息的加密和解密。
在SpringBoot项目中使用jasypt,只需要几个简单的步骤就可以实现我们的需求。
使用
第一步,引入maven依赖
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
第二步,在系统yml中添加配置
jasypt:
encryptor:
algorithm: PBEWithMD5AndDES
iv-generator-classname: org.jasypt.iv.NoIvGenerator
password: *****
- jasypt: 这是Jasypt的配置根节点。
- encryptor: 这指定了加密器的配置。
- algorithm: 这是用于加密的算法。在这里,它设置为PBEWithMD5AndDES。PBE代表基于密码的加密(Password-Based Encryption),它使用密码作为加密密钥的生成基础。MD5是用于从密码生成密钥摘要的哈希函数,而DES是数据加密标准(Data Encryption Standard),是一个对称加密算法。
- iv-generator-classname: 这指定了初始化向量(IV)生成器的类名。IV是某些加密算法(如某些模式的AES)中使用的一个随机值,与密钥一起用于加密过程。这里,它被设置为org.jasypt.iv.NoIvGenerator,这意味着没有使用IV。这是因为PBEWithMD5AndDES算法本身不使用IV。
- password: 这是用于加密和解密的密码。
这个配置使用PBEWithMD5AndDES算法和一个没有IV的生成器来配置Jasypt的加密器,并使用一个密码来进行加密和解密操作。
需要注意的是,上面最后一个属性password,实际直接放到配置文件是不安全的,开发测试环境还可以用一下,而在生产环境,则建议以启动参数的方式传入。
第三步,使用jasypt进行加密
写一个测试类,然后注入一个StringEncryptor对象,调用该对象的加密或解密方法即可,非常简单,至于该对象的初始化、密钥的处理,已经与SpringBoot做了集成,不需要考虑,按前面两步配置即可。
package tech.popsoft.platform.core;
import lombok.extern.slf4j.Slf4j;
import org.jasypt.encryption.StringEncryptor;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* 加密字符串生成工具
* @author wqliu
**/
@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class EncryptorTest {
@Autowired
private StringEncryptor stringEncryptor;
@Test
public void encrypt(){
//加密
String result=stringEncryptor.encrypt("jdbc:mysql://localhost:3306/message_client?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Hongkong");
log.info(result);
//解密
String decrypt = stringEncryptor.decrypt("Z5CuumrsCpqVzxe9CEpKUhPlnuv/NCdy2NHLSpAaa9lhg9OYLSkty6pik3Ji" +
"+3SstoEuZ5HPZE2gSUc1SikjSrZXX89P4gdk9CnnnG+33RYwmRRDO40Wx6oEvTwOAw6zM93BLk/5YPp0b11ZACyPMLeV9QyYYvwopPKcjA3OqVY=");
log.info(decrypt);
}
}
第四步,使用jasypt加密后的信息
这一步其实也很简单,就是把上一步加密后的字符串,放到ENC()内即可,这是jasypt约定的方式,然后……就不用管了,SpringBoot启动时,会自动获取到已经加密的信息,然后解密。
spring:
profiles:
active: dev
datasource:
# 使用druid数据源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: ENC(j1TezWWHvoksv0RT54JQ/ZhwDz5cfbFcpmkMomdvLjl42sRHKTHBkStN6Lp9EMa5jpsLUZPiz22dd6omhl+ad9LnfzhH6XKqjwhVFNv5PyW7AjO2nEtjH04pqzmcMrVH+Mr8tGuQ9zcIykWrJjamOuZENdEOVmd85gdPOZ449nw=)
username: ENC(kfFewSA41LqRv4SQOx5xOA==)
password: ENC(8Q1rJpb1xgf9yXSIxsYw+Q==)
上面讲数据库连接地址、账号、密码都进行的加密,加密后的数据看上去跟乱码一样。
总结
总体来说,使用jasypt将配置文件中的敏感信息加密,大部分工作内部已处理好了,我们仅需要简单配置下就行了,还是非常实用的。
通过这种方式,我们既可以保证敏感信息在配置文件中的安全性,又可以在系统运行时方便地获取到这些信息。同时,由于我们使用的是成熟的工具包,因此也可以避免自己编写加密解密程序可能带来的问题。
扩展
再深入想一下,jasypt已经给我们提供了整体框架,我们如果对其默认实现不满意,可以扩展。小动作是对提供的类进行配置,比如调整加密算法;大动作则是直接自己实现一个类,把StringEncryptor替换掉。