哈希算法是一個(gè)單向函數(shù)。它可以將任何大小的數(shù)據(jù)轉(zhuǎn)化為定長(zhǎng)的“指紋”,并且無(wú)法被反向計(jì)算。另外,即使數(shù)據(jù)源只改動(dòng)了一丁點(diǎn),哈希的結(jié)果也會(huì)完全不同
hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366
這樣的特性使得它非常適合用于保存密碼,因?yàn)槲覀冃枰用芎蟮拿艽a無(wú)法被解密,同時(shí)也能保證正確校驗(yàn)每個(gè)用戶的密碼。
常用戶注冊(cè)和認(rèn)證的流程是這樣的:
1.用戶注冊(cè)一個(gè)帳號(hào).
2.密碼經(jīng)過(guò)哈希加密儲(chǔ)存在數(shù)據(jù)庫(kù)中。只要密碼被寫(xiě)入磁盤(pán),任何時(shí)候都不允許是明文
3.當(dāng)用戶登錄的時(shí)候,從數(shù)據(jù)庫(kù)取出已經(jīng)加密的密碼,和經(jīng)過(guò)哈希的用戶輸入進(jìn)行對(duì)比
4.如果哈希值相同,用戶獲得登入授權(quán),否則,會(huì)被告知輸入了無(wú)效的登錄信息
第4步中,永遠(yuǎn)不要告訴用戶到底是用戶名錯(cuò)了,還是密碼錯(cuò)了。只需要給出一個(gè)大概的提示,比如“無(wú)效的用戶名或密碼”。這可以防止攻擊者在不知道密碼的情況下,枚舉出有效的用戶名。
用于保護(hù)密碼的哈希函數(shù)和你在數(shù)據(jù)結(jié)構(gòu)中學(xué)到的哈希函數(shù)是不同的。比如用于實(shí)現(xiàn)哈希表這之類(lèi)數(shù)據(jù)結(jié)構(gòu)的哈希函數(shù),它們的目標(biāo)是快速查找,而不是高安全性。只有加密哈希函數(shù)才能用于保護(hù)密碼
?破解哈希加密最簡(jiǎn)單的辦法,就是去猜,將每個(gè)猜測(cè)值哈希之后的結(jié)果和目標(biāo)值比對(duì),如果相同則破解成功。兩種最常見(jiàn)的猜密碼的辦法是字典攻擊和暴力攻擊。
字典攻擊需要使用一個(gè)字典文件,它包含單詞、短語(yǔ)、常用密碼以及其他可能用作密碼的字符串。其中每個(gè)詞都是進(jìn)過(guò)哈希后儲(chǔ)存的,用它們和密碼哈希比對(duì),如果相同,這個(gè)詞就是密碼。字典文件的構(gòu)成是從大段文本中分解出的單詞,甚至還包括一些數(shù)據(jù)庫(kù)中真實(shí)的密碼。然后還可以對(duì)字典文件進(jìn)行更進(jìn)一步的處理使它更有效,比如把單詞中的字母替換為它們的“形近字”(hello變?yōu)閔3110)。
? 暴力攻擊會(huì)嘗試每一個(gè)在給定長(zhǎng)度下各種字符的組合。這種攻擊會(huì)消耗大量的計(jì)算,也通常是破解哈希加密中效率最低的辦法,但是它最終會(huì)找到正確的密碼。因此密碼需要足夠長(zhǎng),以至于遍歷所有可能的字符串組合將耗費(fèi)太長(zhǎng)時(shí)間,從而不值得去破解它。
加鹽
可以在密碼中混入一段“隨機(jī)”的字符串再進(jìn)行哈希加密,這個(gè)被字符串被稱(chēng)作鹽值
,這使得同一個(gè)密碼每次都被加密為完全不同的字符串。為了校驗(yàn)密碼是否正確,我們需要儲(chǔ)存鹽值。通常和密碼哈希值一起存放在賬戶數(shù)據(jù)庫(kù)中,或者直接存為哈希字符串的一部分。
要求:用戶創(chuàng)建賬戶或每次修改密碼時(shí),都應(yīng)該重新生成新的鹽值進(jìn)行加密。為了使攻擊者無(wú)法構(gòu)造包含所有可能鹽值的查詢(xún)表,鹽值必須足夠長(zhǎng)。一個(gè)好的做法是使用和哈希函數(shù)輸出的字符串等長(zhǎng)的鹽值,比如SHA256算法的輸出是256bits(32 bytes),那么鹽值也至少應(yīng)該是32個(gè)隨機(jī)字節(jié)。
一個(gè)好的標(biāo)準(zhǔn)的是:鹽值至少和哈希函數(shù)的輸出一樣長(zhǎng);鹽值應(yīng)該被儲(chǔ)存和密碼哈希一起儲(chǔ)存在賬戶數(shù)據(jù)表中。
存儲(chǔ)密碼的步驟
使用CSPRNG生成一個(gè)長(zhǎng)度足夠的鹽值
將鹽值混入密碼,并使用標(biāo)準(zhǔn)的加密哈希函數(shù)進(jìn)行加密,如SHA256
把哈希值和鹽值一起存入數(shù)據(jù)庫(kù)中對(duì)應(yīng)此用戶的那條記錄
校驗(yàn)密碼的步驟
從數(shù)據(jù)庫(kù)取出用戶的密碼哈希值和對(duì)應(yīng)鹽值
將鹽值混入用戶輸入的密碼,并且使用同樣的哈希函數(shù)進(jìn)行加密
比較上一步的結(jié)果和數(shù)據(jù)庫(kù)儲(chǔ)存的哈希值是否相同,如果相同那么密碼正確,反之密碼錯(cuò)誤
當(dāng)用戶忘記密碼的時(shí)候,怎樣進(jìn)行重置?
個(gè)人的觀點(diǎn)是,當(dāng)前所有廣泛使用的密碼重置機(jī)制都是不安全的。如果你對(duì)安全性有極高的要求,比如一個(gè)加密服務(wù),那么不要允許用戶重置密碼。
大多數(shù)網(wǎng)站向那些忘記密碼的用戶發(fā)送電子郵件來(lái)進(jìn)行身份認(rèn)證。首先,需要隨機(jī)生成一個(gè)一次性的令牌,它直接關(guān)聯(lián)到用戶的賬戶。然后將這個(gè)令牌混入一個(gè)重置密碼的鏈接中,發(fā)送到用戶的電子郵箱。最后當(dāng)用戶點(diǎn)擊這個(gè)包含有效令牌的鏈接時(shí),提示他們可以設(shè)置新的密碼。要確保這個(gè)令牌只對(duì)一個(gè)賬戶有效,以防攻擊者從郵箱獲取到令牌后,用來(lái)重置其他用戶的密碼。
令牌必須在15分鐘內(nèi)使用,并且一旦被使用就立即失效。當(dāng)用戶重新請(qǐng)求令牌時(shí),或用戶登錄成功時(shí)(說(shuō)明他還記得密碼),使原令牌失效也是一個(gè)好做法。如果一個(gè)令牌始終不過(guò)期,那么它一直可以用于入侵用戶的帳號(hào)。電子郵件(SMTP)是一個(gè)純文本協(xié)議,并且網(wǎng)絡(luò)上有很多惡意路由在截取郵件信息。在用戶修改密碼后,那些包含重置密碼鏈接的郵件在很長(zhǎng)一段時(shí)間內(nèi)依然缺乏保護(hù)。因此應(yīng)該盡早使令牌過(guò)期,降低把用戶信息暴露給攻擊者的可能。
攻擊者是可以篡改令牌的,所以不要把賬戶信息和失效時(shí)間存儲(chǔ)在里面。這些信息應(yīng)該以不可猜解的二進(jìn)制形式存在,并且只用來(lái)識(shí)別數(shù)據(jù)庫(kù)中某條用戶的記錄。
永遠(yuǎn)不要通過(guò)電子郵件向用戶發(fā)送新密碼,同時(shí)也記得在用戶重置密碼的時(shí)候隨機(jī)生成一個(gè)新的鹽值用于加密,不要重復(fù)使用之前密碼的那個(gè)鹽值。
原文章