安全儲存口令的業界標準:bcrypt 演算法
最後談一談安全保護口令的的標準演算法,這就是 bcrypt 演算法。為了把事情說清楚,分兩篇文章描述:
-
說說 bcrypt 演算法,以及通過PHP的crypt()演算法進一步引數闡述,雖然crypt()演算法已經不推薦使用了,但對於理解 bcrypt 演算法還是非常好的,可以看看它的歷史。
-
在一個系統中,如果有多種開發語言,那麼 bcrypt 演算法是否通用呢?通過 PHP 和 Ptyhon 語言進行描述。
本文主要理解 bcrypt 演算法,bcrypt 演算法可以認為是 KDF 函式的一種實現,也有迭代因子的概念。
bcrypt 演算法基於 Blowfish 塊金鑰演算法,bcrypt 演算法已經有10多年的歷史,而 Blowfish 金鑰演算法更是有20多年的歷史,久經考驗,所以被認為是 Hash 加密口令的標準演算法。
bcrypt 演算法在內部會使用記憶體初始化 hash 過程,由於需要記憶體,雖然在 CPU 上執行很快,但在 GPU 並行運算卻不快,這也減緩了攻擊者的破解速度。
接下去我使用 PHP 語言中的 crypt() 函式介紹如何使用 bcrypt 演算法,如果你對 Hash 保護口令瞭解的不多,那麼使用 crypt() 函式可能會存在很多問題。
首先必須明確 crypt() 函式並不是 bcrypt 演算法,它可以基於多種不同的 Hash 演算法 。
該函式的原型:
string crypt ( string $str [, string $salt ] )
看上去很簡單,但隱藏了很多內容。
如果你僅僅呼叫 crypt(),會根據作業系統版本和 PHP 版本使用相應的 Hash 演算法,而且如果不顯示的輸入 salt,可能會得到一個弱 salt,所以不推薦這樣呼叫 crypt() 函式,因為遮蔽 了很多細節。
那麼如何選定 bcrypt 演算法(Blowfish)、迭代因子、salt,先看一個例子:
if (CRYPT_BLOWFISH == 1) { echo 'Blowfish:' . crypt('abcde', '$2a$07$woshiyigesaltzhi') . "\n"; }
-
表示使用 bcrypt 演算法(注意:如果是 PHP 5.3.7 後續版本,使用 ,修復了安全風險)。
-
07 表示迭代次數為 7 次。
-
最後一個 $ 後面內容為 salt 值。
接下去看看上面程式碼的輸出:
Blowfish:$2a$07$woshiyigesaltzhi$$$$$.lrU488y7E1Xw.JA4uizIu.PBSSe7t4y
也就是說返回值包含了 crypt() 函式相關資訊,比如告訴你使用了 bcrypt 演算法,迭代因子是 7,salt 是 woshiyigesaltzhi$$$$$,剩下的部分就是口令密文。
此處,遺留一個問題,crypt() 運算出來的口令密文包含 salt 是否不安全?這會在下一篇中描述 。
crypt() 也可以使用其它的 Hash 函式,比如:
-
CRYPT_MD5:
-
CRYPT_BLOWFISH: 或
-
CRYPT_SHA256:
-
CRYPT_SHA512:
大家大概明白 crpyt() 函式的使用了,可能使用的時候有點麻煩,所以建議包裝下該函式:
function better_crypt($input, $rounds = 7) { $salt = openssl_random_pseudo_bytes(22); return crypt($input, sprintf('$2a$%02d$', $rounds) . $salt); }
不管怎麼說,crypt() 函式完全基於底層的 C 函式,執行環境也依賴於作業系統和PHP版本,系統和程式碼遷移的時候可能有多種問題,所以 PHP 從 5.5 版本以後建議使用Password Hashing Functions ,這在下一篇會詳細說一下。
最後簡單提下 scrypt 演算法,它是一種新的口令保護演算法,是另外一種思路,被認為是口令保護的業界標準演算法,但由於時間較短,現在建議還是使用bcrypt() 演算法 。
口令保護系列文章:
瞭解我的書《深入淺出HTTPS:從原理的實戰》 ,如果覺得還不錯,還請在豆瓣上做個評論(https://book.douban.com/subject/30250772/,或點選“原文連線”)。