密碼散列安全

本部分解釋使用散列函數(shù)對密碼進行安全處理背后的原因, 以及如何有效的進行密碼散列處理。

為什么需要把應(yīng)用程序中用戶的密碼進行散列化?

當(dāng)設(shè)計一個需要接受用戶密碼的應(yīng)用時, 對密碼進行散列是最基本的,也是必需的安全考慮。 如果不對密碼進行散列處理,那么一旦應(yīng)用的數(shù)據(jù)庫受到攻擊, 那么用戶的密碼將被竊取。 同時,竊取者也可以使用用戶賬號和密碼去嘗試其他的應(yīng)用, 如果用戶沒有為每個應(yīng)用單獨設(shè)置密碼,那么將面臨風(fēng)險。

通過對密碼進行散列處理,然后再保存到數(shù)據(jù)庫中, 這樣就使得攻擊者無法直接獲取原始密碼, 同時還可以保證你的應(yīng)用可以對原始密碼進行相同的散列處理, 然后比對散列結(jié)果。

需要著重提醒的是,密碼散列只能保護密碼 不會被從數(shù)據(jù)庫中直接竊取, 但是無法保證注入到應(yīng)用中的 惡意代碼攔截到原始密碼。

為何諸如 md5()sha1() 這樣的常見散列函數(shù)不適合用在密碼保護場景?

MD5,SHA1 以及 SHA256 這樣的散列算法是面向快速、高效 進行散列處理而設(shè)計的。隨著技術(shù)進步和計算機硬件的提升, 破解者可以使用“暴力”方式來尋找散列碼 所對應(yīng)的原始數(shù)據(jù)。

因為現(xiàn)代化計算機可以快速的“反轉(zhuǎn)”上述散列算法的散列值, 所以很多安全專家都強烈建議 不要在密碼散列中使用這些散列算法。

如果不建議使用常用散列函數(shù)保護密碼, 那么我應(yīng)該如何對密碼進行散列處理?

當(dāng)進行密碼散列處理的時候,有兩個必須考慮的因素: 計算量以及“鹽”。 散列算法的計算量越大, 暴力破解所需的時間就越長。

PHP 5.5 提供了 一個原生密碼散列 API, 它提供一種安全的方式來完成密碼 散列驗證。 PHP 5.3.7 及后續(xù)版本中都提供了一個 ? 純 PHP 的兼容庫。

PHP 5.3 及后續(xù)版本中,還可以使用 crypt() 函數(shù), 它支持多種散列算法。 針對每種受支持的散列算法,PHP 都提供了對應(yīng)的原生實現(xiàn), 所以在使用此函數(shù)的時候, 你需要保證所選的散列算法是你的系統(tǒng)所能夠支持的。

當(dāng)對密碼進行散列處理的時候,建議采用 Blowfish 算法, 這是密碼散列 API 的默認算法。 相比 MD5 或者 SHA1,這個算法提供了更高的計算量, 同時還有具有良好的伸縮性。

如果使用 crypt() 函數(shù)來進行密碼驗證, 那么你需要選擇一種耗時恒定的字符串比較算法來避免時序攻擊。 (譯注:就是說,字符串比較所消耗的時間恒定, 不隨輸入數(shù)據(jù)的多少變化而變化) PHP 中的 == 和 === 操作符strcmp() 函數(shù)都不是耗時恒定的字符串比較, 但是 password_verify() 可以幫你完成這項工作。 我們鼓勵你盡可能的使用 原生密碼散列 API。

“鹽”是什么?

加解密領(lǐng)域中的“鹽”是指在進行散列處理的過程中 加入的一些數(shù)據(jù),用來避免從已計算的散列值表 (被稱作“彩虹表”)中 對比輸出數(shù)據(jù)從而獲取明文密碼的風(fēng)險。

簡單而言,“鹽”就是為了提高散列值被破解的難度 而加入的少量數(shù)據(jù)。 現(xiàn)在有很多在線服務(wù)都能夠提供 計算后的散列值以及其對應(yīng)的原始輸入的清單, 并且數(shù)據(jù)量極其龐大。 通過加“鹽”就可以避免直接從清單中查找到對應(yīng)明文的風(fēng)險。

如果不提供“鹽”,password_hash() 函數(shù)會隨機生成“鹽”。 非常簡單,行之有效。

我應(yīng)該如何保存“鹽”?

當(dāng)使用 password_hash() 或者 crypt() 函數(shù)時, “鹽”會被作為生成的散列值的一部分返回。 你可以直接把完整的返回值存儲到數(shù)據(jù)庫中, 因為這個返回值中已經(jīng)包含了足夠的信息, 可以直接用在 password_verify()crypt() 函數(shù)來進行密碼驗證。

下圖展示了 crypt()password_hash() 函數(shù)返回值的結(jié)構(gòu)。 如你所見,算法的信息以及“鹽”都已經(jīng)包含在返回值中, 在后續(xù)的密碼驗證中將會用到這些信息。


        password_hash 和 crypt 函數(shù)返回值的組成部分,依次為:所選擇的算法,
        算法選項,所使用的“鹽”,
        以及散列后的密碼。