互聯(lián)網(wǎng)公司數據泄露事件已經(jīng)不是什么新鮮事兒了,目前已經(jīng)曝光過(guò)的數據泄露事件至少上百起,其中不乏一線(xiàn)互聯(lián)網(wǎng)公司,比較出名的數據泄露事件就有2011年CSDN的600萬(wàn)用戶(hù)數據泄露事件和2016年的京東12G用戶(hù)數據泄露事件,用戶(hù)數據泄露后最大的危害就是黑客可以通過(guò)竊取到的用戶(hù)名和口令,登錄用戶(hù)賬號,侵害用戶(hù)權益,導致這種結果的直接原因就是受害公司沒(méi)有對用戶(hù)的口令信息進(jìn)行加密處理。如果對用戶(hù)的口令信息進(jìn)行加密存儲,即使數據被拖庫,黑客也無(wú)法還原出原始密碼。
用戶(hù)名口令加密存儲方法有多種,其中哈希算法加密是一種比較常用的簡(jiǎn)單方法。
哈希算法又稱(chēng)摘要算法、散列算法,它通過(guò)一個(gè)函數,把任意長(cháng)度的數據轉換成一個(gè)固定的長(cháng)度的數據串,它是一種單向密碼體制,無(wú)法從逆向還原出原始明文。
哈希算法有多種,比較常用的有MD5、SHA1、SHA256等。MD5用一個(gè)32位的16進(jìn)制字符串表示,雖然目前MD5已經(jīng)被攻破,但是依然很流行;SHA1用一個(gè)40位的16進(jìn)制字符串表示,目前也被攻破,但是相比MD5,被攻破的難度更大一些,SHA256尚未被攻破,比SHA256更加安全,但是越安全的算法越復雜,計算時(shí)間越長(cháng)。
利用哈希算法對用戶(hù)口令加密存儲最簡(jiǎn)單的辦法就是一次哈希加密,python算法如圖1所示:
圖1:一次加密哈希算法
即把用戶(hù)口令簡(jiǎn)單地進(jìn)行哈希計算后進(jìn)行存儲,這樣得到加密后的密碼無(wú)法還原到原始口令,相對安全,但是可以通過(guò)彩虹表查表破譯。彩虹表就是黑客預先計算一些常用口令的md5值,得到一個(gè)反推表,如表1所示:
表1:彩虹表示例
這樣,無(wú)需破解,只需要對比數據庫中的MD5,黑客就能獲得部分弱口令的用戶(hù)賬號信息。
如此一來(lái),如何確保那些弱口令用戶(hù)的賬號安全呢?可以在一次哈希加密的基礎上進(jìn)行“加鹽”處理,所謂“加鹽”就是指在用戶(hù)原始口令后面加一個(gè)復雜“鹽值”,即一個(gè)復雜的固定字符串,python算法如圖2所示:
圖2:加密哈希加鹽算法
這樣即使用戶(hù)的弱口令,也很難通過(guò)彩虹表反推出明文口令,前提是這個(gè)“鹽”不被泄露,因為無(wú)法保證“鹽”的絕對安全,所以這種加密方法也只是相對安全,不是萬(wàn)無(wú)一失的。
該加密方法的硬傷是“鹽值”是固定的,如果“鹽”是隨機的,那么數據的安全性就能更高一些。
PBKDF2(Password-Based Key Derivation Function)算法原理大致相當于在哈希加密基礎上加“隨機鹽”,然后重復進(jìn)行運算,并最終產(chǎn)生密鑰。如果重復的次數足夠大,那么破解的成本就會(huì )變得很高,而“鹽值”的添加也會(huì )增加彩虹表的攻擊難度。PBKDF2函數的定義如圖3所示:
圖3:PBKDF2函數的定義
PBKDF2的算法流程
DK的值由一個(gè)以上的block拼接而成,block的數量是dklen/hlen的值。就是說(shuō)如果PRF輸出的結果比期望得到的密鑰長(cháng)度要短,則要通過(guò)拼接多個(gè)結果以滿(mǎn)足密鑰的長(cháng)度。
DK = T1 || T2 || ... || Tdklen/hlen
而每個(gè)block則通過(guò)函數F得到:Ti = F(Password, Salt, c, i)
在函數F里,PRF會(huì )進(jìn)行c次的運算,然后把得到的結果進(jìn)行異或運算,得到最終的值。
F(Password, Salt, c, i) = U1 ^ U2 ^ ... ^ Uc
第一次,PRF會(huì )使用Password作為key,Salt拼接上編碼成大字節序的32位整型的i作為鹽值進(jìn)行運算。
U1 = PRF(Password, Salt || INT_32_BE(i))
而后續的c-1次則會(huì )使用上次得到的結果作為鹽值。
U2 = PRF(Password, U1)
...
Uc = PRF(Password, Uc-1)
函數F的大致流程如圖4所示:
圖4:函數F流程圖
使用PBKDF2算法時(shí),HASH算法一般選用sha1或者sha256,隨機鹽的長(cháng)度一般不能少于8字節,HASH次數至少也要1000次,這樣安全性才足夠高。一次密碼驗證過(guò)程進(jìn)行1000次HASH運算,對服務(wù)器來(lái)說(shuō)可能只需要1ms,但對于破解者來(lái)說(shuō)計算成本增加了1000倍,而至少8字節隨機鹽,更是把建表難度提升了N個(gè)數量級,使得大批量的破解密碼幾乎不可行,該算法也是美國國家標準與技術(shù)研究院推薦使用的算法。

