Jasypt 開源加密庫使用教程

目錄

Jasypt 加密概述

Jasypt 快速使用

StringEncryptor 加解密

Jasypt 配置詳解


Jasypt 加密概述

1、Jasypt Spring Boot 爲 spring boot 應用程序中的屬性源提供加密支持,出於安全考慮,Spring boot 配置文件中的敏感信息通常需要對它進行加密/脫敏處理,儘量不使用明文,要實現這一點,辦法有很多,自己手動對敏感信息進行加解密也是可以的。

2、有需求就有人奉獻,Jasypt 開源安全框架就是專門用於處理 Spring boot 屬性加密的,在配置文件中使用特定格式直接配置密文,然後應用啓動的時候,Jasypt 會自動將密碼解密成明文供程序使用。

1)Jasypt 加密屬性配置格式:secret.property=ENC(nrmZtkF7T0kjG/VodDvBw93Ct8EgjCA+),ENC() 就是它的標識,程序啓動的時候,會自動解密其中的內容,如果解密失敗,則會報錯。
2)所以獲取這些屬性值和平時沒有區別,直接使用如 @Value("${secret.property}") 獲取即可,取值並不需要特殊處理。

3、jasypt  同一個密鑰(secretKey)對同一個內容執行加密,每次生成的密文都是不一樣的,但是根據根據這些密文解密成原內容都是可以的.

4、jasypt 官網:https://github.com/ulisesbocchio/jasypt-spring-boot。

5、在項目中集成 jasypt-spring-boot 有三種方法:

方法一

1、如果是 Spring Boot 應用程序,使用了註解 @SpringBootApplication 或者 @EnableAutoConfiguration,那麼只需添加 jasypt-spring-boot-starter 依賴,此時整個 Spring 環境就會支持可加密屬性配置(這意味着任何系統屬性、環境屬性、命令行參數,yaml、properties 和任何其他自定義屬性源可以包含加密屬性):

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

方法二

1、如果沒有使用 @SpringBootApplication 或者 @EnableAutoConfiguration,則將 jasypt-spring-boot 添加到類路徑:

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

2、然後將 @EnableEncryptableProperties 添加到配置類中,以便在整個 Spring 環境中啓用可加密屬性:

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

方法三

1、如果不使用 @SpringBootApplication 或者 @EnableAutoConfiguration 自動配置註解,並且不想在整個 Spring 環境中啓用可加密的屬性,則有本方法,首先將以下依賴項添加到項目中:

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

2、然後在配置文件中添加任意數量的 @EncryptablePropertySource 註解,就像使用 Spring 的 @PropertySource 註解一樣:

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

3、或者還可以使用 @EncryptablePropertySources 註解來對 @EncryptablePropertySource 類型的註解進行分組:

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

從 1.8 版起,@EncryptablePropertySource 支持 YAML 文件

Jasypt 快速使用

不管三七二十一,先入個門再說。

第一步

1、第一步就是要獲取密文,就是將需要加密的數據進行加密,方法有很多,官方提供了 jar 包,可以從命令行操作,也可以直接使用代碼進行加密。

2、推薦使用代碼自己加密即可,下面提供一個工具類進行加密,注意事項

1、Jasypt 默認使用 StringEncryptor 解密屬性,所以加密時默認也得使用 StringEncryptor 加密,否則啓動時解密失敗報錯
2、加密與解密對 StringEncryptor 設置的屬性必須要一致,比如加密時使用什麼算法,那麼解密時也得一樣,否則啓動時解密失敗報錯
3、下面使用的加密算法爲 "PBEWithMD5AndDES",官網默認的是 "PBEWITHHMACSHA512ANDAES_256",前者是 md5 加 des 標準加密,後者是 sha512 加 AES 高級加密。

4、如果想使用 “PBEWITHHMACSHA512ANDAES_256” 算法,需要 Java JDK 1.9 及以上支持,或者添加 JCE 無限強度權限策略文件,否則運行會報錯:加密引發異常,一個可能的原因是您正在使用強加密算法,並且您沒有在這個Java虛擬機中安裝Java加密擴展(JCE)無限強權限策略文件。

import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.PBEConfig;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.jasypt.util.text.BasicTextEncryptor;
/**
 * jasypt 加密工具類
 *
 * @author wangmaoxiong
 * @version 1.0
 * @date 2020/5/29 8:46
 */
public class JasyptUtils {
    /**
     * {@link StringEncryptor} 加解密。
     * 同一個密鑰(secretKey)對同一個內容執行加密,生成的密文都是不一樣的,但是根據根據這些密文解密成明文都是可以.
     * 1、Jasypt 默認使用 {@link StringEncryptor} 來解密全局配置文件中的屬性,所以提供密文時,也需要提供 {@link StringEncryptor} 加密的密文
     * 2、{@link StringEncryptor} 接口有很多的實現類,比如常用的 {@link PooledPBEStringEncryptor}
     * 3、setConfig(final PBEConfig config):爲對象設置 {@link PBEConfig} 配置對象
     * 4、encrypt(final String message):加密內容
     * 5、decrypt(final String encryptedMessage):解密內容
     *
     * @param secretKey :密鑰。加/解密必須使用同一個密鑰
     * @param message   :加/解密的內容
     * @param isEncrypt :true 表示加密、false 表示解密
     * @return
     */
    public static String stringEncryptor(String secretKey, String message, boolean isEncrypt) {
        PooledPBEStringEncryptor pooledPBEStringEncryptor = new PooledPBEStringEncryptor();
        pooledPBEStringEncryptor.setConfig(getSimpleStringPBEConfig(secretKey));
        String result = isEncrypt ? pooledPBEStringEncryptor.encrypt(message) : pooledPBEStringEncryptor.decrypt(message);
        return result;
    }
    /**
     * 設置 {@link PBEConfig} 配置對象,SimpleStringPBEConfig 是它的實現類
     * 1、所有的配置項建議與全局配置文件中的配置項保持一致,特別是 password、algorithm 等等選項,如果不一致,則應用啓動時解密失敗而報錯.
     * 2、setPassword(final String password):設置加密密鑰,必須與全局配置文件中配置的保存一致,否則應用啓動時會解密失敗而報錯.
     * 3、setPoolSize(final String poolSize):設置要創建的加密程序池的大小.
     * 4、setAlgorithm(final String algorithm): 設置加密算法的值, 此算法必須由 JCE 提供程序支持
     * 5、setKeyObtentionIterations: 設置應用於獲取加密密鑰的哈希迭代次數。
     * 6、setProviderName(final String providerName):設置要請求加密算法的安全提供程序的名稱
     * 7、setSaltGeneratorClassName:設置 Sal 發生器
     * 8、setIvGeneratorClassName:設置 IV 發生器
     * 9、setStringOutputType:設置字符串輸出的編碼形式。可用的編碼類型有 base64、hexadecimal
     *
     * @param secretKey
     * @return
     */
    private static SimpleStringPBEConfig getSimpleStringPBEConfig(String secretKey) {
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword(secretKey);
        config.setPoolSize("1");
        config.setAlgorithm("PBEWithMD5AndDES");
        config.setKeyObtentionIterations("1000");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        config.setStringOutputType("base64");
        return config;
    }

    public static void main(String[] args) throws Exception {
        String message = "[email protected]";
        String password = "wangmaox";

        //一個同樣的密碼和祕鑰,每次執行加密,密文都是不一樣的。但是解密是沒問題的。
        String jasyptEncrypt = stringEncryptor(password, message, true);
        System.out.println(jasyptEncrypt);

        String jasyptEncrypt1 = stringEncryptor(password, "UVgGJ4BAS8XrVNsamg60RO0ADCzdCKuR2+bvINv7Wyej3YTqVmxp5g1", false);
        System.out.println(jasyptEncrypt1);
    }
}

2、可以直接從 main 方法運行,也可以提供一個 Controller 接口,從瀏覽器訪問:

    /**
     * http://localhost:8080/jasypt/encrypt?secretKey=wangmx&message=修長城的民族&isEncrypt=true
     * 在線使用 {@link StringEncryptor} 加解密消息。
     *
     * @param secretKey :密鑰。加/解密必須使用同一個密鑰
     * @param message   :加/解密的內容
     * @param isEncrypt :true 表示加密、false 表示解密
     * @return
     */
    @GetMapping("jasypt/encrypt")
    public ObjectNode jasyptEncrypt(@RequestParam String secretKey, @RequestParam String message, @RequestParam boolean isEncrypt) {
        String encryptor = JasyptUtils.stringEncryptor(secretKey, message, isEncrypt);
        JsonNodeFactory nodeFactory = JsonNodeFactory.instance;
        ObjectNode objectNode = nodeFactory.objectNode();
        objectNode.put("code", 200);
        objectNode.put("secretKey", secretKey);
        objectNode.put("message", message);
        objectNode.put("isEncrypt", isEncrypt);
        objectNode.put("data", encryptor);
        return objectNode;
    }

第二步

1、全局配置文件中配置如下,必須設置 jasypt.encryptor.password 屬性,algorithm 算法需要與加密時使用的算法一致。

2、想要對哪個屬性進行加密,則使用 ENC() 包裹起來,然後裏面放置密文即可,應用啓動時會自動被解密。

jasypt:
  encryptor:
    password: wangmaox  #加密的密鑰,自定義即可
    algorithm: PBEWithMD5AndDES  #指定解密算法

author:
  infos:
    address: 長沙市天心區
    # Jasypt加密,格式爲ENC(加密結果)
    email: ENC(gqtN4w5o5JrJR0armxigJ+L2HCfPYBVP3Q3rx7ImjDaIuwJA7eMRvw==)

3、對於 Spring Boot 應用,接着不用在做任何設置,程序裏面正常取值即可,不用任何特殊處理,比如也可以對數據源的地址、賬戶、密碼等進行加密,因爲會自動解密,所以不需要擔心取值問題。

@RestController
public class JasyptController {
    @Value("${author.infos.address}")
    private String authorAddress;
    @Value("${author.infos.email}")
    private String authorEmail;
    /**
     * 獲取屬性值
     * http://localhost:8080/jasypt/get
     *
     * @return
     */
    @GetMapping("/jasypt/get")
    public ObjectNode getJasypt() {
        JsonNodeFactory nodeFactory = JsonNodeFactory.instance;
        ObjectNode objectNode = nodeFactory.objectNode();
        objectNode.put("authorAddress", authorAddress);
        objectNode.put("authorEmail", authorEmail);
        return objectNode;
    }

}

StringEncryptor 加解密

1、Jasypt 默認使用 StringEncryptor 解密屬性,所以它默認就已經放置在了 Spring 容器中,可以直接獲取使用,比如除了對配置文件中的屬性加解密後,還可以做其它任何加解密操作,比如下面提供一個 Controller 接口用於在線加解密。

2、因爲瀏覽器地址欄對於特殊字符比較敏感,所以不使用默認的 base64、而改爲使用 16 進制字符串。

jasypt:
  encryptor:
    password: wangmaox  #加密的密鑰,自定義即可,必填項
    algorithm: PBEWithMD5AndDES  #指定解密算法
    string-output-type: hexadecimal #設置加密內容輸出的編碼形式,可用的編碼類型有 base64、hexadecimal(16進制)

3、然後想要使用 StringEncryptor  的地方直接獲取使用即可。

    @Resource
    private StringEncryptor stringEncryptor;

    /**
     * http://localhost:8080/jasypt/encryptor?message=12日下午17點執行任務&isEncrypt=true
     * http://localhost:8080/jasypt/encryptor?message=702EAA3755766C567F62E83273681A90DC684B6AFADD5CD84691778DAF4A1466E13CE0720E8BABC06081A5D6DBD90EA1&isEncrypt=false
     * 在線使用 {@link StringEncryptor} 加解密消息。
     *
     * @param message   加/解密的內容
     * @param isEncrypt true 表示加密、false 表示解密
     * @return
     */
    @GetMapping("jasypt/encryptor")
    public ObjectNode encrypt(@RequestParam String message, @RequestParam boolean isEncrypt) {
        JsonNodeFactory nodeFactory = JsonNodeFactory.instance;
        String encrypt = isEncrypt ? stringEncryptor.encrypt(message) : stringEncryptor.decrypt(message);
        ObjectNode objectNode = nodeFactory.objectNode();
        objectNode.put("code", 200);
        objectNode.put("data", encrypt);
        return objectNode;
    }

Jasypt 配置詳解

1、Jasypt 默認使用 StringEncryptor 解密屬性,如果在 Spring 上下文中找不到自定義的 StringEncryptor,則使用如下默認值:

配置屬性 是否必填項 默認值
jasypt.encryptor.password True -
jasypt.encryptor.algorithm False PBEWITHHMACSHA512ANDAES_256
jasypt.encryptor.key-obtention-iterations False 1000
jasypt.encryptor.pool-size False 1
jasypt.encryptor.provider-name False SunJCE
jasypt.encryptor.provider-class-name False null
jasypt.encryptor.salt-generator-classname False org.jasypt.salt.RandomSaltGenerator
jasypt.encryptor.iv-generator-classname False org.jasypt.iv.RandomIvGenerator
jasypt.encryptor.string-output-type False base64
jasypt.encryptor.proxy-property-sources False false
jasypt.encryptor.skip-property-sources False empty list

2、唯一需要的屬性是 jasypt.encryptor.password ,其餘的可以使用默認值。雖然所有這些屬性都可以在屬性文件中聲明,但爲了安全 password 屬性官方不推薦存儲在屬性文件中,而應作爲系統屬性、命令行參數或環境變量傳遞。

3、官網默認加解密算法爲 "PBEWITHHMACSHA512ANDAES_256",它是 sha512 加 AES 高級加密,需要 Java JDK 1.9 及以上支持,或者添加 JCE 無限強度權限策略文件,否則運行會報錯:加密引發異常,一個可能的原因是您正在使用強加密算法,並且您沒有在這個Java虛擬機中安裝Java加密擴展(JCE)無限強權限策略文件。

此時換成 PBEWithMD5AndDES 算法即可,它是 md5 加 des 標準加密。

4、標準所有的 StringEncryptor 屬性,都可以在全局配置文件中進行配置。也可以在後臺添加 StringEncryptor bean,此時默認的加密程序將被忽略。

import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @author wangmaoxiong
 * @version 1.0
 * @date 2020/5/29 15:24
 */
@Configuration
public class AppConfig {
    /**
     * 自定義 StringEncryptor,覆蓋默認的 StringEncryptor
     * bean 名稱是必需的,從 1.5 版開始按名稱檢測自定義字符串加密程序,默認 bean 名稱爲:jasyptStringEncryptor
     *
     * @return
     */
    @Bean("jasyptStringEncryptor")
    public StringEncryptor jasyptStringEncryptor() {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword("wangmaox");
        config.setAlgorithm("PBEWithMD5AndDES");
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
        return encryptor;
    }
}

請注意,bean 名稱是必需的,因爲 jasypt spring boot 從 1.5 版開始按名稱檢測自定義字符串加密程序,默認 bean 名稱爲:jasyptStringEncryptor

但也可以通過定義屬性來覆蓋,例如 jasypt.encryptor.bean=encryptorBean,然後使用該名稱定義自定義加密程序:

@Bean("encryptorBean") public StringEncryptor stringEncryptor() { ... }

後記:

1、更多內容參考 jasypt 官網:https://github.com/ulisesbocchio/jasypt-spring-boot。

2、也可以參考 https://blog.csdn.net/wangmx1993328/category_10026548.html

3、有人說 jasypt 加密的內容後臺 @Value 取值時可以看到解密的值,或者說 debug 時能看到解密的值,對於開發人員來說自然是可以的,只要加密是可逆的,自然能下毒就能解毒。如果換成生產環境上,就無法 debug 看到明文了呀。

其實關鍵在於加密時使用的密鑰(password),只要密鑰不丟失,密文是有保障的,即便你告訴它使用的算法,它也無濟於事,就像官方說的,密鑰不推薦直接寫在配置文件中,比如可以啓動的時候,通過參數傳入。

4、本文演示源碼:

https://github.com/wangmaoxiong/h2Smil/blob/master/src/main/java/com/wmx/controller/JasyptController.java

https://github.com/wangmaoxiong/h2Smil/blob/master/src/main/java/com/wmx/utils/JasyptUtils.java

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章