前幾天,有個前同事向我吐槽,他們公司有個大神把公司的項目代碼所有上傳到了 github,而且是公開項目,全部人均可以瀏覽。更加恐怖的是項目裏面包含配置文件,數據庫信息、redis 配置、各類公鑰私鑰密碼全在項目裏面,也一同上傳了。java
若是隻是單純的業務代碼泄露,狀況倒還好,由於別人知道你代碼,要想搞你,他必需要把源碼看一遍,分析漏洞。 又由於代碼上線,通過了層層測試,漏洞也很差找,至少短期內很差找。可是別人拿到你的數據庫信息,那就開啓了上帝模式,想怎麼玩就怎麼玩,刪庫都不用跑路的。git
不過,還好他們發現的及時,第一時間刪除了 github 上的項目,可是不能保證當時的項目沒有人拉到本地,因此第二就是把配置文件內的各項配置都更改一遍,改配置聽起來簡單,可是要知道有些配置是不能熱更新的。不少配置要把前一個配置修改後才能使用,新老配置不能共存,你改的瞬間運行的項目就崩了,必需要停機維護才能夠。爲了變動配置他們花了大量的人力物力與精力。github
其實這種慘痛的教訓本能夠避免的,防止配置泄露,通用的有兩種形式。一種是使用配置中心,本地不保存配置,啓動的時候從配置中心獲取,這應該是最優解了。可是不少時候你所作的項目並無使用配置中心,配置就在項目裏面裸奔。這個時候就須要本地加密的形式防止配置泄露了,經常使用框架是 jasypt。同時它也是本文的主題,話很少說,直接開始,看看若是使用 jasypt 進行配置加密。web
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.1</version>
</dependency>
<build>
<plugins>
<plugin>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-maven-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</build>
複製代碼
若是你使用了 spring boot 那麼使用 jasypt 很簡單,只要依賴一個 jasypt-spring-boot-starter 包就能夠了。redis
至於 jasypt-maven-plugin 是方便咱們加密解密配置的 maven 插件,後面會說用法。算法
my.conf.test1=123
my.conf.test2=DEC(123)
# 記得看最佳實踐
jasypt.encryptor.password=lE1rl5K$
複製代碼
總共有三個配置,第一個配置 my.conf.test1 是不須要加密的配置,第二個配置 my.conf.test2 是須要加密的配置,要加密的內容是 123。注意他的格式的是 DEC(待加密內容)。第三個 jasypt.encryptor.password 配置是咱們的加密私鑰,默認使用的加密算法是 PBEWITHHMACSHA512ANDAES_256 ,這個密鑰能夠是任意字符串,而 lE1rl5K$ 只是我隨機生成的,你能夠自由發揮。spring
好了,到目前爲止,咱們的配置仍是明文的。my.conf.test2 是咱們想加密的配置,他與 my.conf.test1 惟一的區別就是多了一個 DEC() 包裹,這算哪門子加密,其實咱們還差一步。還記得咱們上面加依賴的時候,配置了一個 Maven 插件嗎?如今就是用到他的時候,在咱們的項目目錄路徑下執行以下命令:數據庫
mvn jasypt:encrypt -Djasypt.encryptor.password="lE1rl5K$"
複製代碼
注意在執行的時候,password 要換成你本身在上文配置的密鑰。執行完後,看到終端輸出了一大堆日誌,而後就沒有而後了。可是真的是這樣嗎?安全
你再打開 application.properties 看一下,有什麼不同的地方。bash
my.conf.test1=123
my.conf.test2=ENC(0ZWzuD2DH0BZ8ANGMZxQyC6wv84sQLJtE6u7bcRjU+DntbMgkBvE2Z4fSzKKhYN8)
jasypt.encryptor.password=lE1rl5K$
複製代碼
咱們發現,三個配置中其它兩個是原來的樣子,可是 my.conf.test2 變了,首先格式從以前 DEC(xxx) 變成了 ENC(xxx) 。另外括號的 123 變成了 0ZWzuD2DH0BZ8ANGMZxQyC6wv84sQLJtE6u7bcRjU+DntbMgkBvE2Z4fSzKKhYN8 。
這其實就是配置加密後的樣子。這條命令的功能其實很簡單:
另外經過插件也能夠解密,使用
mvn jasypt:decrypt -Djasypt.encryptor.password="lE1rl5K$"
複製代碼
執行這條命令會反過來,把 ENC(xxx) 內容的配置解密成 DEC(明文) 打印在控制檯,注意是控制檯,而不是把配置文件變回去,做者說這樣是爲了安全。
/* * * * * * * * blog.coder4j.cn * * * Copyright (C) 2016-2019 All Rights Reserved. * * * */
package cn.coder4j.study.example.jasypt;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/** * @author buhao * @version TestController.java, v 0.1 2019-12-26 10:55 buhao */
@RestController
@RequestMapping("/test")
public class TestController {
@Value("${my.conf.test1}")
private String confTest1;
@Value("${my.conf.test2}")
private String confTest2;
@GetMapping("/getConf/{type}")
@ResponseBody
public Object getConfTest(@PathVariable Integer type) {
if (type == 1) {
return confTest1;
} else {
return confTest2;
}
}
}
複製代碼
代碼其實很簡單,首先經過 @Value 的方式讀取配置,同時把沒有加密的配置與加密的配置都讀出來,而後經過接口,當路徑參數爲 1 的時候返回沒有通過加密的參數,當路徑參數爲 2 的時候返回加密過的參數。要是都返回 123 說明咱們成功了。
爲了方便驗證,直接用 IDEA 的內置工具,下面是驗證結果:
結果如咱們所料,加密成功。
獲取配置的大體流程其中跟上面加密配置的流程大體反過來:
能夠看到,經過 jasypt 十分的方便,第一依賴,第二配置,其中配置除加密內容外還有一個 jasypt.encryptor.password 。這個前文也說了是用於加密與解密的密碼,經過它能夠加解密配置。
回到開頭,咱們加密的目的是爲了防止代碼泄露的時候把配置一塊兒給泄露出去了。配置是沒有問題了,咱們加密了,可是咱們同時把密鑰也放在配置文件中了。這至關於什麼呢?就像你把門給鎖了,可是鑰匙還插在鎖上。
因此密鑰必定要跟配置分開保存,一般是經過啓動命令傳給應用,好比下面這種:
java -Djasypt.encryptor.password="password" -jar my-application.jar
複製代碼
若是再保險一點,能夠把密鑰放在環境變量中,再經過命令傳給應用。
默認使用的加密算法爲對稱加密 HHMAC ,既然有對稱那確定也有非對稱。
這裏的對稱與非對稱指的是密鑰的保存方式,對稱加密是指的是加密與解密共用一個密鑰,也就是說我用這個密鑰便可以用來加密也能夠用來解密。上一條說爲了安全咱們要把配置跟密鑰分開保存,通常保存在兩個地方,一個是線上服務器,一個是項目負責人的電腦上了,由於他要把配置從明文變成密文。爲何是項目負責人的電腦上,由於密鑰不可能人手一份,那樣又會增大泄露風險。
可是這樣的話又會出來一種問題,一個項目涉及了太多配置,我加一個配置找下項目負責人幫我生成個密文,加一個生成一個,項目負責人變成工具人了。
這個時候咱們能夠經過非對稱加密的方式來解決,這種方式的好處就是有一對密碼,分別稱爲公鑰與私鑰,公鑰用來生成加密數據,能夠放心大膽人手一份,而私鑰放在服務器上進行運行時候的解密工做,因篇幅有限,具體使用方式能夠經過文末的連接查看官方文檔。
配置確定是區分環境的,有些環境安全等級沒有那麼高,好比開發與測試環境,沒有必要加密。而預發及生產環境就須要加密,而且推薦使用不一樣的密鑰,這樣最大程度的避免安全問題。