前言
在Spring Boot項(xiàng)目中,應(yīng)該會(huì)用到很多的配置屬性,這些屬性中難免會(huì)有敏感信息,比如數(shù)據(jù)庫(kù)賬號(hào)、密碼、域名、redis密碼等等。為了安全起見,可以結(jié)合Jasypt這個(gè)庫(kù),對(duì)敏感屬性實(shí)現(xiàn)加密處理。
引入的依賴
這里筆者的環(huán)境是spring boot 2.1.7,引用的Jasypt版本為3.0.2,具體如下:
<dependency> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-spring-boot-starter</artifactId> <version>3.0.2</version> </dependency>
如何加密
首先,添加Jasypt的專屬配置屬性,最基本也是最需要的一個(gè)屬性password,告訴Jasypt一個(gè)“鹽值”吧,它會(huì)根據(jù)提供的鹽值,按照指定的加密算法,對(duì)敏感配置屬性進(jìn)行加密解密。除了指定鹽值,Jasypt還提供了更多屬性,可以指定加密算法等等。具體可以參照J(rèn)asypt在Github上的Readme。
那么告訴Jasypt鹽值后,怎樣來對(duì)自己的敏感配置進(jìn)行加密呢?目前筆者知道有這么2種方式。
Maven插件
Jasypt提供了一個(gè)Maven插件,最基本的功能就是可以用這個(gè)插件對(duì)敏感屬性值進(jìn)行加密。當(dāng)然這個(gè)插件還有其他更強(qiáng)的功能,可以自行深入研究。
pom.xml中添加該插件:
<plugin> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-maven-plugin</artifactId> <version>3.0.2</version> </plugin>
執(zhí)行下面的命令,對(duì)敏感屬性值進(jìn)行加密。
mvn jasypt:encrypt-value -Djasypt.encryptor.password="#$!_" -Djasypt.encryptor.algorithm="PBEWithMD5AndDES" -Djasypt.plugin.value="test"
jasypt.encryptor.password,告訴Jasypt你提供的鹽值。
jasypt.encryptor.algorithm,告訴Jasypt用哪個(gè)算法加密。
jasypt.plugin.value,告訴Jasypt加密的值什么。
測(cè)試類
這種方式是自己手寫一個(gè)測(cè)試類,在這個(gè)測(cè)試類中用測(cè)試代碼的方式執(zhí)行加密處理,輸出加密結(jié)果。因?yàn)橛玫氖莏asypt-spring-boot-starter,默認(rèn)它會(huì)提供一個(gè)StringEncryptor來做加解密處理??梢岳肧tringEncryptor來加密敏感配置屬性。
需要添加配置屬性,讓測(cè)試代碼運(yùn)行時(shí)能夠“感知”到。
jasypt.encryptor.password=#$!_ #根據(jù)需要指定合適的加密算法,不指定會(huì)采用默認(rèn)算法 #jasypt.encryptor.algorithm=PBEWithMD5AndDES
測(cè)試代碼示例如下:
@RunWith(SpringRunner.class) @SpringBootTest(classes = Application.class) public class EncryptTest { @Autowired private StringEncryptor stringEncryptor; @Test public void encrypt() { String encryptStr = stringEncryptor.encrypt("localhost:3306"); System.out.println(encryptStr); encryptStr = stringEncryptor.encrypt("mysql_account"); System.out.println(encryptStr); encryptStr = stringEncryptor.encrypt("mysql_password"); System.out.println(encryptStr); } }
如何解密
加密后的屬性值,按照要求格式進(jìn)行替換,比如把原先的redis密碼屬性修改如下:
spring.redis.password=ENC(ACjcb1s5O0g+yaxSrktQIK3qTTrpwhVojaYDM23pClE=)
ENC(...)是Jasypt解密時(shí)的標(biāo)識(shí),里面放的是加密后的值,Jasypt見到這個(gè)標(biāo)識(shí)后會(huì)里面的加密值進(jìn)行解密處理。當(dāng)然這個(gè)ENC(...)標(biāo)識(shí)是支持自定義的,具體看最后的參考鏈接。
解密之前,還需要告訴Jasypt,加密時(shí)使用的鹽值和加密算法。所以不要忘了上面提到的這兩個(gè)屬性。
jasypt.encryptor.password=#$!_ #根據(jù)需要指定合適的加密算法,不指定會(huì)采用默認(rèn)算法 #jasypt.encryptor.algorithm=PBEWithMD5AndDES
遇見的異常
由于筆者用的Jasypt版本是3.0.2,如果你用的也是一樣的話,那么使用上述的加密、解密方式,你應(yīng)該會(huì)遇到下面的異常。大概意思是你需要在你本地JDK里安裝JCE。
因?yàn)镴asypt的2.x版本,jasypt.encryptor.algorithm默認(rèn)值為PBEWithMD5AndDES,而3.x版本中,該屬性的默認(rèn)值為PBEWITHHMACSHA512ANDAES_256。
那么你可以安裝JCE,或者指定jasypt.encryptor.algorithm值為PBEWithMD5AndDES。
org.jasypt.exceptions.EncryptionOperationNotPossibleException: Encryption raised an exception. A possible cause is you are using strong encryption algorithms and you have not installed the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files in this Java Virtual Machine at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.handleInvalidKeyException(StandardPBEByteEncryptor.java:1207) at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.encrypt(StandardPBEByteEncryptor.java:996) at org.jasypt.encryption.pbe.StandardPBEStringEncryptor.encrypt(StandardPBEStringEncryptor.java:655) at org.jasypt.encryption.pbe.PooledPBEStringEncryptor.encrypt(PooledPBEStringEncryptor.java:465) at com.ulisesbocchio.jasyptspringboot.encryptor.DefaultLazyEncryptor.encrypt(DefaultLazyEncryptor.java:110)
更進(jìn)一步的安全思考
基本上Jasypt加解密就簡(jiǎn)單描述完畢了,其實(shí)Jasypt就是依賴提供的鹽值及指定的算法來進(jìn)行加解密的。假設(shè)這個(gè)鹽值被暴露了,那么所謂的加密也是不安全的。
筆者目前有2種思路來更進(jìn)一步的提升加密安全。Jasypt加解密所依賴的屬性值,應(yīng)該避免直接在屬性文件中暴露,可以選擇配置到環(huán)境變量中,或者配置到命令行的參數(shù)中。
Linux中配置環(huán)境變量
具體如何在Linux系統(tǒng)中配置環(huán)境變量,可以參考這里。
Spring Boot應(yīng)用配置啟動(dòng)參數(shù)
筆者用的是Spring Boot Maven插件打包出的可運(yùn)行jar包,在線上環(huán)境中可以輕松地配置為服務(wù),在對(duì)應(yīng)的.conf文件中添加啟動(dòng)參數(shù),參考如下:
RUN_ARGS="--jasypt.encryptor.password=&$!_ --jasypt.encryptor.algorithm=PBEWithMD5AndDES"
具體筆者部署Spring Boot應(yīng)用的方式,可看這里學(xué)習(xí)。
待研究的一個(gè)現(xiàn)象
筆者采用如下的Jasypt屬性配置,對(duì)“123456”分別進(jìn)行了兩次加密輸出,得到的值是不一樣的。
jasypt.encryptor.password=#$!_ #根據(jù)需要指定合適的加密算法,不指定會(huì)采用默認(rèn)算法 jasypt.encryptor.algorithm=PBEWithMD5AndDES
兩次加密的結(jié)果,分別是:
I3H2AZaME7KgI5d0JHWR/27MN1WFRsJd
vCuFGjOUzWYYgIiNniuH2HxC7h2EB7BW
拿這兩次的結(jié)果分別去解密,結(jié)果是否都是“123456”呢?親測(cè),是的!
來源:https://juejin.cn/post/6844904162648391693