Spring Security 中的 BCryptPasswordEncoder

l_lOct發表於2024-03-23

一、使用BCryptPasswordEncoder加密的值可以解出來嗎

  Spring Security 中的 BCryptPasswordEncoder 是一種單向加密演算法,它是為了安全性考慮而設計的,因此無法從加密後的密碼值"解密"出原始密碼。這是出於安全目的的設計。

  BCryptPasswordEncoder 加密過程是不可逆的,即使你有加密後的密碼值,也無法透過任何方式獲得原始密碼。這種單向加密的目的就是為了防止密碼洩露後被破解。

  通常,在實際應用中,我們只需要將使用者輸入的原始密碼使用 BCryptPasswordEncoder 進行加密,然後將加密後的密碼值儲存在資料庫中。在使用者登入時,將使用者輸入的密碼加密後,與儲存在資料庫中的加密密碼進行比對,如果相同則驗證透過,而無需知道原始密碼。

  因此,你無法從 BCryptPasswordEncoder 加密後的密碼值中"解密"出原始密碼。這正是它被設計用於密碼加密的目的,以提高系統的安全性。如果你需要知道使用者的原始密碼,建議在註冊時不對密碼進行加密,或者提供"忘記密碼"的功能讓使用者重置密碼。

二、為什麼每次BCryptPasswordEncoder加密的值不一樣,卻可以都匹配上原始密碼

  這是因為 BCryptPasswordEncoder 在加密時會自動新增一個隨機的 Salt 值,這個 Salt 值的作用是使得相同的原始密碼在每次加密時產生不同的密文,從而增加密碼的安全性。

  具體來說,BCryptPasswordEncoder 加密過程包括以下幾個步驟:

    1. 生成一個隨機的 Salt 值,通常是 16 位元組長度。
    2. 將原始密碼和 Salt 值進行合併。
    3. 對合並後的值進行 BCrypt 雜湊運算,計算出最終的密文。
    4. 將 Salt 值和密文拼接在一起,作為最終的加密結果。

  因此,每次加密相同的原始密碼時,由於使用了不同的隨機 Salt 值,所以最終的加密結果也是不同的。

  在驗證密碼時,BCryptPasswordEncoder 會自動從加密結果中提取出 Salt 值,並使用相同的方式對輸入的原始密碼進行加密,然後比較兩個密文是否相同。由於使用了相同的 Salt 值,所以即使每次加密後的結果不同,只要原始密碼相同,透過 BCrypt 演算法計算出的密文就是相同的。

  這種機制不僅增加了密碼的安全性,而且還能防止採用相同密碼的不同使用者的密文相同,從而增加了"彩虹表"攻擊的難度。所以即使每次加密結果不同,BCryptPasswordEncoder 依然能夠正確比對密碼。

三、BCryptPasswordEncoder 加密結果的格式

  在 BCryptPasswordEncoder 加密後的結果中,前 29 個字元是包含了 Salt 值和其他演算法資訊的部分,後面的字串才是實際的密文部分。

  具體來說,BCryptPasswordEncoder 加密結果的格式是:

$演算法標識$rounds$salt$密文

  其中:

  • `$演算法標識` 是一個固定的字串 `$2a$`、`$2b$` 或 `$2y$`等,用於標識使用的雜湊演算法版本。
  • `$rounds` 是一個十進位制數字,表示演算法迭代的次數。
  • `$salt` 是一個 22 個字元長的 Base64 編碼的字串,這就是加密時使用的隨機 Salt 值。
  • `$密文` 是實際的密文部分,長度為 31 個字元。

  例如,一個典型的 BCryptPasswordEncoder 加密結果可能是:

    

$2a$10$N9qo8uHh24cuh6zT6ZsEfe6Fzen7kNSNBqh.FkQPvQUNhxfrasXTi

  在這個加密結果中:

  • `$2a$` 表示使用 BCrypt 演算法的版本 2a
  • `10` 表示迭代次數為 10
  • `N9qo8uHh24cuh6zT6ZsEfe` 就是 22 個字元長的隨機 Salt 值
  • 最後 31 個字元 `6Fzen7kNSNBqh.FkQPvQUNhxfrasXTi` 才是實際的密文部分

  所以,BCryptPasswordEncoder 加密結果中,第 4 到第 25 個字元就是隨機生成的 Salt 值。每次加密相同的密碼,這部分 Salt 值都會不同,從而導致最終的加密結果也不相同。但在驗證時,會自動提取出這個 Salt 值用於計算,所以能夠正確比對密碼。

四、Salt 值和真實密碼合併後的值進行 BCrypt 雜湊運算,如果知道salt值和最終的密文可以解出原來的密碼嗎

  即使知道了Salt值和最終的密文,也無法透過任何方式反解出原始的密碼。

  這是因為BCrypt是一種經過加鹽(Salting)的單向自適應金鑰匯出函式(Key Derivation Function),它的設計目的就是使得從密文反推原始密碼是計算上不可行的。

  具體來說,BCrypt演算法包含以下幾個關鍵設計:

    1. 使用了Eksblowfish演算法作為核心,這是一種金鑰設定可變的塊加密演算法,具有良好的密碼學性質。
    2. 在金鑰設定中引入了可變的迭代次數,預設為2^10次,這使得暴力破解的計算代價大大增加。
    3. 在金鑰設定中引入了隨機的Salt值,使得相同的密碼每次產生的密文都不同,防止彩虹表攻擊。
    4. 金鑰設定過程是自適應和可變的,可以根據硬體效能動態調整計算代價。
    5. 最終密文使用Base64編碼,長度為53個字元,其中包含了Salt和其他演算法引數。

  因此,即使已知Salt值和密文,要反解出原始密碼,仍然需要進行大量的計算和暴力破解。由於BCrypt演算法設計的目的就是使這種破解行為在計算上不可行,所以實際上是無法透過任何方式從Salt和密文中反解出原始密碼的。

  這就是BCrypt作為密碼雜湊演算法的設計理念和安全保證。除非原始密碼非常簡單且Salt和迭代次數設定較低,否則從BCrypt密文中反解是極其困難的。

相關文章