在 Java 中使用 Argon2 進行哈希處理
一、概述
在構建涉及用戶身份驗證的 Web 應用程序時,保護用戶免受黑客攻擊非常重要。大多數 Web 應用程序的設計目的不是存儲純文本密碼,而是存儲密碼的散列值。散列和加鹽是幫助保護密碼免受任何可能的攻擊的技術。
在本教程中,我們將學習散列和加鹽技術,以及如何在 Java 中使用 Argon2 進行散列。
2.密碼散列和加鹽
密碼散列和加鹽是兩種可以加強存儲在數據庫中的密碼安全性的技術。散列算法涉及將密碼更改或轉換為隨機字符串的數學運算。
但是,黑客可以通過比較常用密碼的哈希值來嘗試猜測密碼。為了防止這種情況,密碼加鹽開始發揮作用。
密碼加鹽是在應用哈希算法之前將隨機數據(稱為鹽)附加到密碼的方法。 salt 確保哈希值是不同的,並且具有相同密碼的兩個用戶將具有不同的哈希值。
此外,散列算法是單向的,這意味著散列不能轉換回純文本,這與加密不同。這增加了另一層安全和保護。
3. 什麼是 Argon2?
Argon2 是一個基於密碼的密鑰推導函數。這是一個安全的密碼散列函數,設計有許多可以調整的參數。此外, Argon2 是一個 memory-hard 函數,這意味著它需要大量的內存來計算,並且很難在內存有限的硬件上實現。
此外,它允許應用程序根據其安全需求自定義算法。這對於具有不同安全要求的應用程序至關重要。
此外,由於 Argon2 提供高安全性,因此建議將其用於需要強密碼保護的應用程序。它可以抵抗來自 GPU 和其他專用硬件的攻擊。
4. 用 Argon 散列 2
Argon2 的一大優勢就是我們可以根據不同的需求進行配置。我們可以設置迭代次數。這是密碼將被散列的次數。迭代次數越多,散列密碼的時間越長,但密碼更安全。
此外,我們可以設置內存成本。這是 Argon2 將使用的內存量。更高的內存成本將使密碼更安全,但會消耗更多的系統內存。
此外,我們還可以設置並行度成本。這是 Argon2 算法將使用的線程數。較高的並行成本將加快密碼散列過程,但會降低密碼安全性。
在以下小節中,我們將使用 Spring Security Crypto 庫和 Bouncy Castle 庫通過 Argon2 實現散列。
4.1.使用 Spring Security Crypto 實現 Argon2 哈希
Spring Security Crypto 庫有一個使用 Argon2 散列密碼的類。它在內部依賴於 Bouncy Castle 庫。
讓我們使用 Spring Security Crypto 庫來散列密碼。首先,我們需要將它的依賴添加到pom.xml
中:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
<version>6.0.3</version>
</dependency>
接下來,讓我們看一個基於 Argon2 對密碼進行哈希處理的單元測試:
@Test
public void givenRawPassword_whenEncodedWithArgon2_thenMatchesEncodedPassword() {
String rawPassword = "Baeldung";
Argon2PasswordEncoder arg2SpringSecurity = new Argon2PasswordEncoder(16, 32, 1, 60000, 10);
String springBouncyHash = arg2SpringSecurity.encode(rawPassword);
assertTrue(arg2SpringSecurity.matches(rawPassword, springBouncyHash));
}
在上面的示例中,我們聲明了一個變量來存儲原始密碼“ Baeldung
”。接下來,我們創建一個帶有五個參數的Argon2PasswordEncoder
實例。我們將要使用的迭代次數設置為 10,並將散列長度設置為 32 字節。默認哈希長度為 64 字節。此外,我們將內存成本設置為60000
KB,將並行度設置為一個線程,並將時間成本設置為16
迭代。
最後,我們驗證原始密碼是否與散列密碼匹配。
4.2.使用 Bouncy Castle 實現 Argon2 哈希
與 Spring Security Crypto 庫相比,Bouncy Castle 庫的實現更底層。要使用 Bouncy Castle 庫,我們需要將其依賴項添加到pom.xml
中:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
讓我們看一個使用 Bouncy Castle 庫實現散列的示例。
首先,讓我們創建一個方法來為我們生成隨機鹽:
private byte[] generateSalt16Byte() {
SecureRandom secureRandom = new SecureRandom();
byte[] salt = new byte[16];
secureRandom.nextBytes(salt);
return salt;
}
在上面的示例代碼中,我們創建了一個SecureRandom
對象,它是一個提供加密強隨機數生成器的類。接下來,我們創建一個大小為16
byte
數組來存儲 16 個字節的數據。然後,我們調用secureRandom
上的nextBytes()
方法來生成鹽。
最後,讓我們散列密碼“ Baeldung
”:
@Test
public void givenRawPasswordAndSalt_whenArgon2AlgorithmIsUsed_thenHashIsCorrect() {
byte[] salt = generateSalt16Byte();
String password = "Baeldung";
int iterations = 2;
int memLimit = 66536;
int hashLength = 32;
int parallelism = 1;
Argon2Parameters.Builder builder = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id)
.withVersion(Argon2Parameters.ARGON2_VERSION_13)
.withIterations(iterations)
.withMemoryAsKB(memLimit)
.withParallelism(parallelism)
.withSalt(salt);
Argon2BytesGenerator generate = new Argon2BytesGenerator();
generate.init(builder.build());
byte[] result = new byte[hashLength];
generate.generateBytes(password.getBytes(StandardCharsets.UTF_8), result, 0, result.length);
Argon2BytesGenerator verifier = new Argon2BytesGenerator();
verifier.init(builder.build());
byte[] testHash = new byte[hashLength];
verifier.generateBytes(password.getBytes(StandardCharsets.UTF_8), testHash, 0, testHash.length);
assertTrue(Arrays.equals(result, testHash));
}
在上面的示例中,我們使用generatesalt16Byte()
方法創建了一個隨機的 16 字節鹽。接下來,我們定義算法的基本參數,例如迭代次數、內存限制、散列長度、並行度因子和 salt 。
然後,我們創建一個Argon2BytesGenerator
對象。此對像有助於生成密碼哈希。此外,我們定義一個byte
數組來存儲生成的哈希結果。
最後,我們創建另一個Argon2BytesGenerator
實例來將結果與測試哈希進行比較。這斷言密碼哈希是正確的,並且可以通過 Argon2 算法進行驗證。
5.結論
在本文中,我們學習了密碼散列和加鹽的基礎知識。此外,我們深入研究了 Argon2 算法,並看到了使用 Spring Security Crypto 和 Bouncy Castle 的實現。 Spring Security Crypto 看起來很簡單,因為它抽象了一些過程。
與往常一樣,示例的完整源代碼可在 GitHub 上獲得。