【哈希算法】

哈希值

哈希值,一般翻譯做"散列值",也有直接音譯為"哈希值"的,就是把任意長度的輸入(又叫做預(yù)映射,pre-image),通過散列算法,變換成固定長度的輸出,該輸出就是散列值。這種轉(zhuǎn)換是一種壓縮映射,也就是,散列值的空間通常遠(yuǎn)小于輸入的空間,不同的輸入可能會散列成相同的輸出,而不可能從散列值來唯一的確定輸入值。簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要的函數(shù)。

哈希算法

哈希算法(Hash)又稱摘要算法(Digest),它的作用是:對任意一組輸入數(shù)據(jù)進(jìn)行計(jì)算,得到一個固定長度的輸出摘要。

哈希算法的特點(diǎn)

哈希算法的輸出長度是固定的,與輸入數(shù)據(jù)的長度無關(guān)。
無法從哈希值推算出原始輸入數(shù)據(jù)。
不同的輸入可能會產(chǎn)生相同的哈希值,這種情況稱為哈希碰撞。

哈希碰撞

哈希碰撞是指,兩個不同的輸入得到了相同的輸出:

"AaAaAa".hashCode(); // 0x7460e8c0
"BBAaBB".hashCode(); // 0x7460e8c0

有童鞋會問:碰撞能不能避免?答案是不能。碰撞是一定會出現(xiàn)的,因?yàn)檩敵龅淖止?jié)長度是固定的,String的hashCode()輸出是4字節(jié)整數(shù),最多只有4294967296種輸出,但輸入的數(shù)據(jù)長度是不固定的,有無數(shù)種輸入。所以,哈希算法是把一個無限的輸入集合映射到一個有限的輸出集合,必然會產(chǎn)生碰撞。

碰撞不可怕,我們擔(dān)心的不是碰撞,而是碰撞的概率,因?yàn)榕鲎哺怕实母叩完P(guān)系到哈希算法的安全性。一個安全的哈希算法必須滿足:

碰撞概率低;
不能猜測輸出。

不能猜測輸出是指,輸入的任意一個bit的變化會造成輸出完全不同,這樣就很難從輸出反推輸入(只能依靠暴力窮舉)。假設(shè)一種哈希算法有如下規(guī)律:

hashA("java001") = "123456"
hashA("java002") = "123457"
hashA("java003") = "123458"

那么很容易從輸出123459反推輸入,這種哈希算法就不安全。安全的哈希算法從輸出是看不出任何規(guī)律的:

hashB("java001") = "123456"
hashB("java002") = "580271"
hashB("java003") = ???

常用的哈希算法有:

算法

根據(jù)碰撞概率,哈希算法的輸出長度越長,就越難產(chǎn)生碰撞,也就越安全。

SHA

SHA算法是Secure Hash Algorithm的縮寫,是一種密碼學(xué)哈希函數(shù),用于產(chǎn)生散列值,常用于數(shù)據(jù)加密和驗(yàn)證的安全應(yīng)用中。SHA算法可以將任意長度的輸入信息轉(zhuǎn)換為固定長度的輸出值,這種輸出值又稱為散列值或摘要

哈希算法的用途

因?yàn)橄嗤妮斎胗肋h(yuǎn)會得到相同的輸出,因此,如果輸入被修改了,得到的輸出就會不同。
我們在網(wǎng)站上下載軟件的時候,經(jīng)??吹较螺d頁顯示的哈希:

如何判斷下載到本地的軟件是原始的、未經(jīng)篡改的文件?我們只需要自己計(jì)算一下本地文件的哈希值,再與官網(wǎng)公開的哈希值對比,如果相同,說明文件下載正確,否則,說明文件已被篡改。

哈希算法的另一個重要用途是存儲用戶口令。如果直接將用戶的原始口令存放到數(shù)據(jù)庫中,會產(chǎn)生極大的安全風(fēng)險(xiǎn):

  • 數(shù)據(jù)庫管理員能夠看到用戶明文口令;
  • 數(shù)據(jù)庫數(shù)據(jù)一旦泄漏,黑客即可獲取用戶明文口令。

不存儲用戶的原始口令,那么如何對用戶進(jìn)行認(rèn)證?

方法是存儲用戶口令的哈希,例如,MD5。

在用戶輸入原始口令后,系統(tǒng)計(jì)算用戶輸入的原始口令的MD5并與數(shù)據(jù)庫存儲的MD5對比,如果一致,說明口令正確,否則,口令錯誤。
因此,數(shù)據(jù)庫存儲用戶名和口令的表內(nèi)容應(yīng)該像下面這樣:



這樣一來,數(shù)據(jù)庫管理員看不到用戶的原始口令。即使數(shù)據(jù)庫泄漏,黑客也無法拿到用戶的原始口令。想要拿到用戶的原始口令,必須用暴力窮舉的方法,一個口令一個口令地試,直到某個口令計(jì)算的MD5恰好等于指定值。

彩虹表攻擊

使用哈??诹顣r,還要注意防止彩虹表攻擊。

彩虹表是一個用于加密散列函數(shù)逆運(yùn)算的預(yù)先計(jì)算好的表,為破解密碼的散列值(或稱哈希值、微縮圖、摘要、指紋、哈希密文)而準(zhǔn)備。彩虹表是馬丁·赫爾曼早期提出的簡單算法的應(yīng)用。
彩虹表常用于恢復(fù)由有限集字符組成的固定長度的純文本密碼。彩虹表越大,破解密碼越有效越迅速。但是彩虹表對于其它破解方法(如碰撞)和可變長密鑰等現(xiàn)代高級算法,效果會大打折扣。使用加salt的KDF函數(shù)可以使彩虹表破解密碼的方法難以實(shí)現(xiàn)。

上面講到了,如果只拿到MD5,從MD5反推明文口令,只能使用暴力窮舉的方法。
然而黑客并不笨,暴力窮舉會消耗大量的算力和時間。但是,如果有一個預(yù)先計(jì)算好的常用口令和它們的MD5的對照表:


這個表就是彩虹表。如果用戶使用了常用口令,黑客從MD5一下就能反查到原始口令:

bob的MD5:f30aa7a662c728b7407c54ae6bfd27d1,原始口令:hello123;
alice的MD5:25d55ad283aa400af464c76d713c07ad,原始口令:12345678;
tim的MD5:bed128365216c019988915ed3add75fb,原始口令:passw0rd。

這就是為什么不要使用常用密碼,以及不要使用生日作為密碼的原因。

即使用戶使用了常用口令,我們也可以采取措施來抵御彩虹表攻擊,方法是對每個口令額外添加隨機(jī)數(shù),這個方法稱之為加鹽(salt):

digest = md5(salt+inputPassword)

經(jīng)過加鹽處理的數(shù)據(jù)庫表,內(nèi)容如下:


加鹽的目的在于使黑客的彩虹表失效,即使用戶使用常用口令,也無法從MD5反推原始口令。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容