首頁 > 軟體

SpringBoot整合Jasypt敏感資訊加密的操作方法

2022-05-24 14:02:17

前言

在網際網路遍佈社會各個角落的時代,伴隨著的是安全問題總是層出不窮。 19年4月,根據深圳市人民檢察院微信訊息,深圳某知名無人機企業的工程師因為洩露公司原始碼到開源社群Github上而造成了公司巨大的損失,最終被判處有期徒刑6個月,罰款20萬元。

一般公司的核心業務程式碼中,都會存在與資料庫、第三方通訊的secret key等敏感資訊,如果以明文的方式儲存,一旦洩露,那將會給公司帶來巨大的損失。 然而,許多中小型公司開發者對這方面的管理不夠規範,所以很多敏感資訊都是直接以明文形式存放到程式碼中,這樣的專案存在的安全風險非常大。

本篇文章通過講解:Springboot整合Jasypt對專案敏感資訊進行加密,提高系統的安全性。

哪些資訊需要加密

一個系統中,一般和資料庫、第三方系統等互動的資訊都會存在相應的組態檔中,在組態檔中,所有涉及到資訊保安的設定項都不應該以明文的形式儲存,否則,一旦組態檔洩露,則會引出巨大的安全問題,常見的需要加密的資訊項如下:

  • 存取資料庫、快取等涉及到的賬號密碼
  • 與第三方系統互動的access key、祕鑰
  • 其他涉及第三方通訊的資訊

敏感資訊加密的作用

第一:是為了防止人為誤操作將程式碼洩漏時,第三方能夠簡單獲取到系統中的敏感資訊,從而可能對系統、資料庫等造成破壞。

其次是一般系統上線都會有程式碼安全檢測的流程,像賬號、密碼等敏感資料以明文形式儲存,一般都是稽核不通過的,因此需要進行加密處理。

最後,作為一名開發者,應該對自我有更高的要求,在開發過程中應該要考慮到潛在的風險,提供相應的處理預案。

選擇加密的元件

開源社群強大之處在於:有需求就有人奉獻。Jasypt(全稱:Java Simplified Encryption),它是一個Java類庫,支援開發者無需深入 瞭解密碼學相關工作原理,花費最小的程式碼在專案中新增基本的加密功能。

Jasypt官方使用檔案:http://www.jasypt.org/

專案整合Jasypt方式

jasypt-spring-boot元件則是Jasypt提供對Springboot專案整合的依賴,剛好符合我們的需求,它支援以下3種方式整合到專案中。

方式一

在Springboot應用程式中,如果使用了@SpringBootApplication or @EnableAutoConfiguration註解,則可以直接在pom檔案中新增jasypt-spring-boot依賴,然後就可以在整個Spring環境中使用jasypt對屬性進行加解密操作(屬性包括:系統屬性、環境屬性、命令列引數、properties、yml以及任何其他屬性源)。

<dependency>
        <groupId>com.github.ulisesbocchio</groupId>
        <artifactId>jasypt-spring-boot-starter</artifactId>
        <version>3.0.4</version>
</dependency>

方式二

如果專案中沒有使用到@SpringBootApplication or @EnableAutoConfiguration註解,則可以通過以下兩個步驟完成對Jasypt的整合。

步驟一:pom檔案引入jasypt依賴

<dependency>
        <groupId>com.github.ulisesbocchio</groupId>
        <artifactId>jasypt-spring-boot</artifactId>
        <version>3.0.4</version>
</dependency>

步驟二:在設定類中,新增@EnableEncryptableProperties註解,範例如下:

@Configuration
@EnableEncryptableProperties
public class MyApplication {
    ...
}

通過這種方式,你的專案一樣可以整合Jasypt,並且可加密屬性也可以在整個Spring環境中啟用(屬性包括:系統屬性、環境屬性、命令列引數、properties、yml以及任何其他屬性源)。

方式三

如果專案中沒有使用到@SpringBootApplication or @EnableAutoConfiguration註解,又不想在整個Spring環境中啟用加密的屬性,則可以使用該種方式,具體步驟如下:

步驟一:pom檔案引入jasypt依賴

<dependency>
        <groupId>com.github.ulisesbocchio</groupId>
        <artifactId>jasypt-spring-boot</artifactId>
        <version>3.0.4</version>
</dependency>

步驟二、在設定類中,使用@EncryptablePropertySource註解新增任意數量想要生效加密屬性的組態檔路徑,與Spring中@PropertySource註解的使用類似,範例如下:

@Configuration
@EncryptablePropertySource(name = "EncryptedProperties", value = "classpath:encrypted.properties")
public class MyApplication {
	...
}

同時,還可以使用@EncryptablePropertySources 註解對@EncryptablePropertySource設定進行分組,範例如下:

@Configuration
@EncryptablePropertySources({@EncryptablePropertySource("classpath:encrypted.properties"),                         @EncryptablePropertySource("classpath:encrypted2.properties")})
	public class MyApplication {
		...
	}

說明:從Jasypt 1.8版本開始,@EncryptablePropertySource註解支援設定YAML檔案

Springboot整合Jasypt實戰

一、引入依賴

說明,本專案使用技術棧是spring-boot+jasypt,故使用上面介紹的第一種方式來在專案中整合Jasypt,文章中只擷取部分核心程式碼,全部程式碼會開發到Github和Gitee上。

<dependency>
	<groupId>com.github.ulisesbocchio</groupId>
	<artifactId>jasypt-spring-boot-starter</artifactId>
	<version>3.0.4</version>
</dependency>

二、組態檔中新增Jasypt設定資訊

1、設定jasypt引數

jasypt:
  encryptor:
    # 設定加密演演算法
    algorithm: PBEWithMD5AndDES
    iv-generator-classname: org.jasypt.iv.NoIvGenerator
    property:
      # 演演算法識別字首(當演演算法發現組態檔中的值以這字首開始,字尾結尾時,會使用指定演演算法解密)
      prefix: IT(
      # 演演算法識別字尾
      suffix: )

2、設定加密演演算法祕鑰 (該祕鑰不能直接放在組態檔中,下面會具體總結祕鑰存放的方式,從而保證安全性)

三、使用Jasypt對資料庫賬號和密碼加密,並替換明文。

替換後的設定資訊:

spring:
  application:
    name: Jasypt-Learning
  datasource:
    url: jdbc:mysql://localhost:3306/user2?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai
    username: IT(MIJueAfnYWsKa2kiR8Qrrw==)
    password: IT(qH9m5vjj8RYULOASKdhlOw==)
server:
  port: 9090
# 設定jasypt相關資訊
jasypt:
  encryptor:
    # 設定加密演演算法
    algorithm: PBEWithMD5AndDES
    iv-generator-classname: org.jasypt.iv.NoIvGenerator
    property:
      # 演演算法識別字首(當演演算法發現組態檔中的值以這字首開始,字尾結尾時,會使用指定演演算法解密)
      prefix: IT(
      # 演演算法識別字尾
      suffix: )

Jasypt加密有3種方式,具體如下:

方式1、使用程式碼生成加密串,程式碼工具如下:

public static void main(String[] args) {
        String username = encrypt("root");
        String password = encrypt("123456");
        System.out.println(username);
        System.out.println(password);
    }
    /**
     * 加密
     * @param plaintext 明文密碼     * @return
     */
    public static String encrypt(String plaintext) {
        //加密工具
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        //加密設定
        EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();
        // 演演算法型別
        config.setAlgorithm("PBEWithMD5AndDES");
        //生成祕鑰的公鑰
        config.setPassword("PEB123@321BEP");
        //應用設定
        encryptor.setConfig(config);
        //加密
        String ciphertext = encryptor.encrypt(plaintext);
        return ciphertext;
    }
    /**
     * 解密
     *
     * @param ciphertext 待解密祕鑰
     * @return
     */
    public static String decrypt(String ciphertext) {
        //加密工具
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        //加密設定
        EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();
        config.setAlgorithm("PBEWithMD5AndDES");
        //生成祕鑰的公鑰
        config.setPassword("PEB123@321BEP");
        //應用設定
        encryptor.setConfig(config);
        //解密
        String pText = encryptor.decrypt(ciphertext);
        return pText;
    }

方式2、使用java cp命名對加密生成密文

引數說明:

  • org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI是jasypt提供的一個用於加密的實體類
  • org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI是jasypt提供的一個用於解密的實體類
  • input表示需要加密的字串如:密碼
  • password表示本次加密演演算法使用的祕鑰
  • algorithm表示加密演演算法的名稱。

特別說明: 通過該種方式獲取密文,需要到maven倉庫下jasypt-1.9.3.jar包所在的路徑下執行,否則會報找不到對應的主類。

// 加密命令
java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input='root' password=abcdef algorithm=PBEWithMD5AndDES

// 解密命令
java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringDecryptionCLI input='z4xP29fuY4wF2AJqp1NnoGJxj' password=abcdef algorithm=PBEWithMD5AndDES

方式3、使用jasypt-maven外掛生成密文

該外掛是jasypt官方提供,在pom中新增對應依賴,然後使用mvn命令即可執行加解密操作,具體如下:

// 1、在Pom中新增maven外掛依賴
<plugin>
	<groupId>com.github.ulisesbocchio</groupId>
	<artifactId>jasypt-maven-plugin</artifactId>
	<version>3.0.4</version>
</plugin>

// 2、加密命令
mvn jasypt:encrypt-value -Djasypt.encryptor.password="祕鑰的值" -Djasypt.plugin.value="需要加密的敏感資訊"

// 解密命令
mvn jasypt:decrypt-value -Djasypt.encryptor.password="祕鑰的值" -Djasypt.plugin.value="需要解密的密文"

四、檢視執行結果

使用中的一些坑

使用過程中遇到了許多不可預估的問題,特意總結出來,方便讀者參考。

1、使用jasypt3.0啟動時報:Failed to bind properties under ‘xxx.xxx.xxx’ to java.lang.String

官方描述,3.0後預設支援的演演算法為PBEWITHHMACSHA512ANDAES_256 ,該種加密方式由sha512 加 AES 高階加密組成,需要JDK1.9以上支援或者新增JCE(Java Cryptography Extension無限強度許可權策略檔案)支援,否則執行會出現錯誤。

解決方式:

方式1、將加密演演算法替換成PBEWithMD5AndDES 演演算法,並設定iv-generator-classname: 為org.jasypt.iv.NoIvGenerator值

方式2、降低jasypt的版本 - 使用2.x的版本

2、加解密祕鑰如何儲存

如果祕鑰寫在程式碼或者組態檔,一旦程式碼洩露,那別人就可以使用祕鑰解密我們的密文,這樣對敏感資訊加密的作用就不存在了,因此,祕鑰不能以明文形式儲存在程式碼或者組態檔中,下面就介紹一些安全的儲存祕鑰的形式。

方式1、把祕鑰當做程式啟動時的命令列引數(推薦),範例如下:

java -jar xxx.jar --jasypt.encryptor.password=祕鑰

方式2、把祕鑰當做程式啟動時環境變數(推薦),範例如下:

java  -Djasypt.encryptor.password=祕鑰 -jar xxx.jar

方式3、自定義加密、解密器邏輯(這個自定程式碼,本文不展開講解,後續有需要重開一篇文章詳細講解)

如何避免Git洩露

因為開發者的疏漏,不小心將原始碼提交到開源倉庫中的新聞不在少數,作為一個開發團隊,如何採取一些有效的措施去最小程度防止出現這種情況呢? 除了本文介紹的對敏感資訊加密,併合理儲存祕鑰外,還有以下的一些方式可以參考。

方式1、更規範的程式碼提交、推播制度、培養開發者的安全意識: 很多時候,程式碼的洩露除了故意為之外,大多數是因為不小心導致,因此在專案中可以通過合理管控許可權的方式來防止程式碼洩露。

方式2、合理利用Git忽略檔案(.gitignore): 通過gitignore檔案設定匹配規則,最大程度避免敏感資訊上傳到Git倉庫。

方式3、藉助第三方工具,在提交、推播時檢測程式碼是否有敏感資料: 常見的如git-secrets,在提交前會對變更內容做檢測,如果檢測到預期的提交內容可能包含敏感資訊,那它們將會拒絕提交。

方式4、程式碼的Code Review: 團隊leader和成員之間可以互相合作,在程式碼推播合併時檢測是否存在敏感資料,這樣不僅可以排查出敏感資料,還能夠學習彼此之間的一些編碼技巧。

問題探討

在編寫本篇文章內容時,無意中看到一個訊息:Nginx之父被俄羅斯警方帶走,起因是因為其老東家 Rambler舉報Nginx是他在就職期間的業務時間進行開發的一個軟體,Rambler認為其應該有該軟體程式碼的所有權。

針對這一事件大家有什麼看法呢?程式設計師在就職期間的業務時間開發或者編寫的專案應該歸屬於公司?歡迎在文章下留言討論。

寫在最後

原始碼安全在技術企業中意味著競爭力、生命線,一旦洩露,輕則造成專案失敗,重則可能導致公司倒閉,這一關檢測的重要性不言而喻,作為一名開發者,也應該時刻培養自己的安全意識,在編碼時規避掉相應的風險。

到此這篇關於SpringBoot整合Jasypt加密敏感資訊的文章就介紹到這了,更多相關SpringBoot加密敏感資訊內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com