使用Jasypt对springboot项目的配置属性加密。
简书地址
写这篇的目的不是为了创新,而是备忘,最近学习clojure,java基本上已经放下了,但是曾今用过的东西如果不记录一下,以后用起来估计连查什么关键字都不知道了,因此在主页上做个笔记。
原来我们写的springboot的配置文件大概是这样的
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&useSSL=false
username: root
password: 123456
怎么看也是赤裸裸的,大概你也想过要是能加密就好了,如果只是想想的话,肯定不会自己加密,这里就介绍个非常方便易用的加密工具jasypt。
常规使用
在springboot中引入依赖
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
修改后的配置文件
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&zeroDateTimeBehavior=convertToNull&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&tinyInt1isBit=false
# 对应用户名 root ,密码 123456
username: ENC[KHRM9dKY8KykzzYbt8rRZQ==]
password: ENC[RWmQMxlcukotJAb36PrKSA==]
jasypt:
encryptor:
# 任意的随机字符串均可
password: SBPstLlrFzXW01Okb62R95qvpj4J83Dn
property:
# 自定义属性规则,默认前缀是“ENC(”,后缀为“)”
prefix: "ENC["
suffix: "]"
这里只加密了用户名和密码,其实所有属性,报过jdbc的url也是可以用同样的方式加密的。
留意到上面这段配置的用户名和密码是 ENC[xxx] 这种格式的,其中 ENC[] 是自定义配置的,这也是 Jasypt 能正常识别待解密数据的规则,那其中的加密串又是从哪来的呢?
当然是运算出来的。最简单的配置,开发者只需要再补充完 jasypt.encryptor.password=xxx 属性即可(同上,还支持使用 DER、PEM 这种证书的 private/public keys 加解密方式),具体的生成代码在下方:
@Slf4j
@SpringBootApplication
@EnableEncryptableProperties
public class JasyptSpringBootApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(JasyptSpringBootApplication.class, args);
JasyptSpringBootApplication application = context.getBean(JasyptSpringBootApplication.class);
// 这里可以将明文(用户名、密码)转换成相应密文
application.jasypt("root");
application.jasypt("123456");
// 不过程序最后还是通过明文信息进行数据库连接
HikariDataSource hikariDataSource = (HikariDataSource) context.getBean(DataSource.class);
log.info("DB username: {} , password: {}", hikariDataSource.getUsername(), hikariDataSource.getUsername());
}
@Resource
private StringEncryptor stringEncryptor;
public void jasypt(String text) {
// 即使是相同明文,但这里每次生成的都是不同的密文
String encryptedText = stringEncryptor.encrypt(text.trim());
String decryptedText = stringEncryptor.decrypt(encryptedText);
log.info("ORIGINAL: {} ; ENCRYPTED: {} ; DECRYPTED: {}", text, encryptedText, decryptedText);
}
}
在开发环境要切换jdbc,或者看看密码到底是啥,为啥报jdbc链接错误时,可以用这个
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;
import javax.annotation.Resource;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MobileOfficeApplication.class)
@Slf4j
public class MobileOfficeApplicationTests {
//@Test
public void te(){
System.out.println(userService.encodePwd());
}
@Autowired
private StringEncryptor stringEncryptor;
@Test
public void contextLoads() {
}
@Test
public void testEncrypt() {
System.out.println("=====================================");
System.out.println("key1:" + stringEncryptor.encrypt("jdbc:p6spy:mysql://127.0.0.1:3306/chuangke?characterEncoding=utf-8&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Hongkong&autoReconnect=true\n"));
System.out.println("key2:" + stringEncryptor.encrypt("root"));
System.out.println("key3:" + stringEncryptor.encrypt("root"));
System.out.println("=====================================");
}
}
进阶
上面的例子是将password设置在与密文一起的配置文件中,这样方便是方便,但是有密码,有密文,知道加密算法,谁也可以解密呀(安全是相对的,其实这个已经很不错了),那有么有更安全的方式呢?
当然有!!!!
有两种办法:
- 部署时设置password
为了防止salt(盐)泄露,反解出密码.可以在项目部署的时候使用命令传入salt(盐)值
java -jar -Djasypt.encryptor.password=G0CvDz7oJn6 xxx.jar
- 将password配置到服务器的环境变量里
# 打开/etc/profile文件
vim /etc/profile
#文件末尾插入
export JASYPT_PASSWORD = G0CvDz7oJn6
#编译
source /etc/profile
#运行
java -jar -Djasypt.encryptor.password=${JASYPT_PASSWORD} xxx.jar