亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

加密模塊

1. 前言

我們知道安全性的實現往往少不了加解密的參與,Spring Security 加密模塊支持對稱加密、秘鑰生成和密碼編碼。這些代碼被發布在 Spring Security 核心模塊當中,與其他模塊或代碼之間零耦合。

本節主要討論 Spring Security 中的加密模塊。

圖片描述

2. 加密器

加密器的相關類提供了構造對稱加密器的工廠方法。通過該類,我們可以創建 ByteEncryptor 用于加密原始字節流內容,我們也可以構建出 TextEncryptor 用于加密文本字符串,這些加密器都是線程安全的。

2.1 BytesEncryptor

BytesEncryptor 是通過 Encryptors.stronger 工廠方法構造出的:

Encryptors.stronger("password", "salt");

stronger 加密方法構造了一個使用GCM模式的 256 位 AES 算法加密器。它使用 PKCS #5 的 PBKDF2(基于密碼的密鑰派生函數 #2)導出密鑰(此方法需要 Java 6)。方法中 password 參數用于生產加密密鑰,它將被保存在一個不被共享的安全區域。salt 參數用于避免字典攻擊。除此之外,此處還應用了 16 字節的隨機初始化向量來保證每個加密消息都是唯一的。

salt 參數的是一個 16 禁止編碼字符串,具有隨機性,至少有 8 位長,salt 可以通過以下方式生成:

String salt = KeyGenerators.string().generateKey(); // 生成一個隨機 8 位長的 16 進制字符串

我們也可以使用標準加密方法,即 CBC 模式的 256 位 AES 算法加密模式。這種模式不需要通過身份認證,也無法保證數據的真實性,相對 Encryptors.stronger 來說安全性會低一些。

2.2 TextEncryptor

使用 Encryptors.text 工廠方法構造標準的文本加密器 TextEncryptor

Encryptors.text("password", "salt");

TextEncryptor 使用的是標準 BytesEncryptor 來加密文本數據,加密的結果以 16 進制編碼字符串形式返回,這樣容易被文件系統或數據庫保存。

我們也可以使用 Encryptors.queryableText 工廠方法構建可查詢的文本加密器:

Encryptors.queryableText("password", "salt");

這兩種加密器間的區別是擁有不同的初始化向量(iv)處理。在可查詢文本加密器中,初始化向量是可共享的、固定的,并且不是隨機生成的。這意味著相同的文本內容多次被加密的結果是相同的。這樣的場景的安全性相對較低,但有時為了加密出的結果是有規律的,比如希望他仍然可以被再次查詢到,還是需要用到這樣的加密方式??刹樵兾谋炯用芷鞯氖褂脠鼍坝腥?OAuth 的 apiKey。

3. 秘鑰生成器

密鑰生成器(KeyGenerators)提供了一些工廠方法,用于構造不同類型的密鑰生成器。例如 BytesKeyGenerator 可用于生產 byte[] 類型密鑰。StringKeyGenerator 用于生成字符串類型密鑰。密鑰生成器是線程安全的。

3.1 BytesKeyGenerator

使用 KeyGenerators.secureRandom 工廠方法構造 BytesKeyGenerator 實例:

BytesKeyGenerator generator = KeyGenerators.secureRandom();
byte[] key = generator.generateKey();

默認配置下,生成的 key 長度為 8 位,我們也可以為 secureRandom 設置參數來修改生成密鑰長度:

KeyGenerators.secureRandom(16);

使用 KeyGenerators.shared 工廠方法構造 BytesKeyGenerator 可以使多次生成的密鑰內容相同。

KeyGenerators.shared(16);

3.2 StringKeyGenerator

使用 KeyGenerators.string 工廠方法可以構造 8 為長的隨機 16 禁止字符串密碼:

KeyGenerators.string();

4. 密碼編碼

在 Spring Security 加密模塊中,password 包提供了編碼密碼的方法。PasswordEncoder 是其中的核心類:

public interface PasswordEncoder {
	String encode(String rawPassword);
	boolean matches(String rawPassword, String encodedPassword);
}

matches 方法用來判斷密碼原文在經過一次編碼后,與密碼密文是否匹配,這個方法用于基于密碼認證的場景。

最常見的實現類是 BCryptPasswordEncoder,它使用了 bcrypt 算法來散列密碼。Bcrypt 使用了一個隨機 16 位鹽值,用于制造冗余,以防止密碼被破解。冗余次數可以通過 strength 參數設置,其值為 4~31 之間,值約高,散列次數越多,默認值為 10。

// 構造一個強度為 16 的密碼加密器
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));

Pbkdf2PasswordEncoder 實現了 PBKDF2 算法用來散列密碼。該算法為了防止被破解,有意的減慢了執行時間,大概需要 0.5 秒完成密碼的驗證。

// 創建一個 PBKDF2 算法的密碼加密器
Pbkdf2PasswordEncoder encoder = new Pbkdf2PasswordEncoder();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));

5. 小結

本節討論了 Spring Security 安全框架中的加解密實現,主要內容有:

  • Spring Security 在核心模塊中包含了一個關于加密算法的包,其包含了加密、密鑰生成、密碼編碼三個主要功能;
  • Spring Security 的加密主要分基于 byte[] 對象的加密和文本形式的加密;
  • Spring Security 的加密可分為冪等的和非冪等的,其分別有各自的應用場景;
  • Spring Security 對密碼的加密采取了有意拖延的方式,防止密碼被暴力破解。

下節討論在 Spring Security 項目中,如何實現單元測試。