## 關於Jasypt
就是java套件,用於當專案布置時,可以把配置文件中的敏感資訊替換成密文,啟動專案時帶入密鑰才能正常解密運行,避免敏感資訊明文顯示,這裡只有簡單使用,然後最好一開始配置就帶入jasypt,不然只要上版控(Git)就還要把舊的紀錄清除,很麻煩
## 使用方式
整體流程是:
-> 先手動把需要加密的明文手動經過加密(帳號、密碼...)
-> 放上配置文件用ENC(密文)的方式寫<font style='color:red;'>※</font>

-> 專案啟動類加上@EnableEncryptableProperties才會自動解密

-> 啟動專案時帶上加密的密鑰
範例為springboot + maven
先加依賴
```java=
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
//(這邊主要是用3以後,3以前差異好像蠻大我也不了解)
<version>3.0.4</version>
</dependency>
```
這邊加密是直接寫在測試類(JUnit5),運行時也可以順便測試加解密正常
```java=
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.iv.RandomIvGenerator;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class JasyptEncodeTest {
@Test
@DisplayName("測試Jasypt加密解密")
void jasyptEncodeDecode() {
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
//jasypt解密時默認是用RandomIvGenerator做向量,但這邊預設是null所以要指定
encryptor.setIvGenerator(new RandomIvGenerator());
encryptor.setPassword("testEncode"); // 加密密鑰
String originUrl = "testUrl";
String originUsername = "testUsername";
String originPassword = "testPassword";
String dbUrl = encryptor.encrypt(originUrl);
String dbUsername = encryptor.encrypt(originUsername);
String dbPassword = encryptor.encrypt(originPassword);
System.out.println("加密----------------------------------------");
System.out.println("Encrypted text: [" + dbUrl + "]");
System.out.println("Username text: [" + dbUsername + "]");
System.out.println("Password text: [" + dbPassword + "]");
System.out.println("-------------------------------------------");
Assertions.assertEquals(originUrl, encryptor.decrypt(dbUrl));
Assertions.assertEquals(originUsername, encryptor.decrypt(dbUsername));
Assertions.assertEquals(originPassword, encryptor.decrypt(dbPassword));
}
}
```
比較要注意的是encryptor.setIvGenerator(new RandomIvGenerator());
這部分一定要做設置,因為加密時和解密時的默認方式不一樣,很奇怪,我也這樣覺得
運行成功之後把輸出的密文寫到配置類上並且寫成ENC(密文)<font style='color:red;'>※</font>

然後這邊還需要加一個配置就是
```java=
//jasypt3以上會以PBEWITHHMACSHA512ANDAES_256為默認算法,和加密時StandardPBEStringEncryptor默認的PBEWithMD5AndDES算法不同,所以這邊要指定
jasypt.encryptor.algorithm=PBEWithMD5AndDES
```
之後就是專案啟動時設置密鑰,專案就會自動解密配置ENC()包裹的密文
簡單啟動的話就是
```
//mvn打包
mvn clean install
//啟動時帶入密鑰
java "-Djasypt.encryptor.password=密鑰" -jar XXX.jar
```
或是可以使用環境變數的方式寫密鑰,這邊就不提
## 錯誤原因
主要會發生的其實就幾個問題
1. 沒有帶入密鑰

2. 解密錯誤


自己排查可能原因就幾個
如果確認加密解密的密鑰相同,就繼續往下看

▲這是什麼配置都不做時,專案啟動默認<font style='color:red;'>解密</font>方式

▲然後這是<font style='color:red;'>加密</font>類默認加密方式
除了單純密鑰錯誤的問題外,會導致差異的屬性主要就是algorithm(算法)和ivGeneratorSet(向量), 看看ChatGpt的說明

所以現在要做的就是<font style='color:red;'>同步加密解密方式</font>
1. 設定成相同加密算法
2. 設定相同的向量算法
我的作法就是加密時設定向量成解密默認方式RandomIvGenerator(浮動向量)
也可以把解密配置設定成NoIvGenerator(不加向量)
然後後解密的算法設置成加密類的默認算法PBEWithMD5AndDES
或是也可以更改加密算法,總而言之就是<font style='color:red;'>必須同步兩邊</font>
## 清除Git紀錄
當今天不小心把加密前的明文推上版控,後續就算用jasypt加密蓋過去還是可以從commit紀錄看到舊的明文,所以勢必得要清除紀錄才能保證安全性
這邊就要用到<font style='color:red;'>Git filter-repo</font>
[當然還是有其他清除的方式啦](https://ithelp.ithome.com.tw/m/articles/10279857), 但我就沒試過了
### Git filter-repo
是官方推薦用於修改commit的插件,得另外安裝
安裝方式有兩種
1. 透過python pip安裝
2. 官方Git下載
這邊不多講,詳細直接看官方[Github](https://github.com/newren/git-filter-repo)
相關安裝都完成後
<font style='color:red;'>先把要處理的檔案做備份</font>(要整個檔案備份)
先說明後續流程
1. 下指令刪除本地commit紀錄(也會刪除指定本地檔案, 所以上面才說要先做備份)
2. 本地的所有commit都要重新push到遠端repository覆蓋掉所有舊的紀錄
(就可以刪去所有帶有敏感資訊的檔案紀錄)
3. 本地,把剛剛被移除的<font style='color:red;'>備份檔案</font>更改成加密後的版本, 重新下commit,當成全新的檔案push到遠端repository
4. 這樣就可以更新成功,清除之前推送過的敏感資訊
---
<font style='color:red;'>※</font>有一個問題要特別注意,就是切換分支的問題,假設我有<font style='color:red;'>主分支A</font>,<font style='color:red;'>A</font>下了一個<font style='color:red;'>commit#123</font>,之後從<font style='color:red;'>A切出了branch B</font>,今天如果==git filter-repo==去修改<font style='color:red;'>B的#123</font>,==git push --force==推上遠端repository後,會導致<font style='color:red;'>A的#123</font>紀錄也被同步更改,<font style='color:red;'>因為git是用commit的hash去追蹤,只要推送紀錄是相同的commit就算切分支,該紀錄被刪除還是會同步連動</font>
---
接下來開始下指令
1. 檢查git filter-repo有沒有安裝成功
```
git filter-repo --version
```
2. sensitive-file為指定要刪除包含敏感資訊的檔案,要指定對的路徑, ex:src/main/java/resource/sensitiveFile.properties
```
git filter-repo --path <sensitive-file> --invert-paths
//如果有多個要刪除的檔案, 重複多個--path
git filter-repo --path <sensitive-file1> --path <sensitive-file2> --invert-paths
```
3. 推送本地[localBranchName]分支commit覆蓋遠端[repositoryName]的分支
```
git push --force [repositoryName] [localBranchName]
```
4. 剩下就是更改新檔案,然後正常下commit,正常push