當前位置:成語大全網 - 漢語詞典 - 如何安全地存儲密碼

如何安全地存儲密碼

保護密碼的最好方法是散列(加鹽密碼散列)。哈希密碼是壹件非常簡單的事情,但是很多人都會犯錯誤。接下來希望我能詳細說明壹下密碼怎麽散列合適,為什麽。

重要提醒

如果妳打算自己寫壹段代碼哈希密碼,那就趕緊收手吧。犯錯誤太容易了。這個提醒適用於所有人,不要自己寫密碼哈希算法!對於保存密碼的問題,有壹個成熟的解決方案,就是使用phpass或者本文提供的源代碼。

哈希是什麽?

hash(" hello ")= 2 cf 24 DBA 5 FB 0 a 30 e 26 e 83 B2 AC 5b 9 e 29 e 161e5c 1fa 7425 e 73043362938 b 9824

hash(" hbllo ")= 58756879 c 05 c 68 dfac 9866712 fad 6a 93 f 8146 f 337 a 69 AFE 7 DD 238 f 3364946366

hash("華爾茲")= c0e 81794384491161f 1777 c 232 BC 6 BD 9 EC 38 f 616560 b 120 FDA 8 e 90 f 383853542

哈希算法是單向函數。它可以將任意數量的數據轉換成固定長度的“指紋”,這是不可逆的。而且只要輸入發生變化,哪怕只有壹位,輸出的哈希值也會大不相同。這個功能正好適合保存密碼。因為我們要用不可逆的算法對保存的密碼進行加密,同時需要在用戶登錄時驗證密碼是否正確。

在使用hash的賬戶系統中,用戶註冊和認證的壹般過程如下:

1,用戶自己創建賬號。

2.哈希運算後,用戶密碼存儲在數據庫中。沒有明文密碼存儲在服務器的硬盤上。

3.當用戶登錄時,用戶輸入的密碼被散列並與存儲在數據庫中的密碼散列值進行比較。

4.如果哈希值完全相同,則認為用戶輸入的密碼是正確的。否則,將認為用戶輸入了無效密碼。

5.每當用戶嘗試登錄時,重復步驟3和4。

第四步不要告訴用戶賬號或密碼是否錯誤。只顯示壹般提示,比如賬號或密碼不正確。這可以防止攻擊者枚舉有效的用戶名。

還應該註意,用於保護密碼的哈希函數與數據結構類中看到的哈希函數並不完全相同。比如實現哈希表的哈希函數設計,速度很快,但是不夠安全。只有加密哈希函數可用於哈希密碼。此類功能包括sha256、sha512、ripemd、whirlpool等。

壹個常見的概念是,密碼經過哈希處理後會安全存儲。這顯然是不正確的。有許多方法可以從哈希中快速恢復明文密碼。還記得那些md5破解的網站嗎,妳只需要提交壹個hash,不到壹秒就知道結果了。顯然,簡單的散列密碼還遠遠不能滿足我們的安全需求。下壹部分首先討論破解密碼哈希獲取明文的常用手段。

如何破解hash

字典和暴力攻擊。

破解哈希最常見的方法是猜測密碼。然後哈希每壹個可能的密碼,將需要破解的哈希與猜測的密碼哈希值進行比較。如果兩個值相同,那麽之前猜測的密碼就是正確的密碼明文。常見的猜測密碼攻擊方法有字典攻擊和暴力攻擊。

字典攻擊

嘗試蘋果:失敗

嘗試藍莓:失敗

嘗試justinbeiber:失敗

...

嘗試letmein:失敗

嘗試s3cr3t:成功!

字典攻擊是將常用的密碼、單詞、短語等可能用作密碼的字符串放入壹個文件中,然後對文件中的每個單詞進行哈希處理,並將這些哈希與需要破解的密碼哈希進行比較。這種方法的成功率取決於密碼字典的大小和字典的適當性。

暴力攻擊

嘗試aaaa:失敗

嘗試aaab:失敗

嘗試aaac:失敗

...

嘗試acdb:失敗

嘗試acdc:成功!

暴力攻擊是對給定的密碼長度嘗試每壹種可能的字符組合。這種方法需要花費大量的計算機時間。但理論上,只要有足夠的時間,最終的密碼肯定會被破解。只是密碼太長的話,破解的時間會難以承受。

目前沒有辦法阻止字典攻擊和暴力攻擊。我們只能想辦法讓他們效率低下。如果妳的密碼哈希系統被設計成安全的,那麽破解哈希的唯壹方法就是進行字典或者暴力攻擊。

查找表

對於特定的哈希類型,如果需要破解大量的哈希,查表是壹種非常有效快速的方式。它的思想是預先計算密碼字典中每個密碼的哈希。然後將散列和相應的密碼存儲在壹個表中。壹個設計良好的查詢表結構,即使存儲了幾十億個散列,也能每秒查詢幾百個散列。

如果妳想感受壹下查表破解hash,可以試試在CraskStation上破解下面的sha256 hash。

c 11083 B4 b 0 a 7743 af 748 c 85d 343 dfe 9 fbb 8 b 2576 c 05 F3 a 7 f 0d 632 b 0926 aadfc

08 EAC 03 b 80 ADC 33 DC 7d 8 FBE 44 b 7 c 7 b 05d 3a 2c 51166 BDB 43 fcb 710 b 03 ba 919e 7

e4ba 5 CBD 251 c 98 e6cd 1 c 23 f 126 a3 b 81d8d 8328 ABC 95387229850952 B3 ef 904

5206 b8b 8 a 996 cf 5320 CB 12ca 91c7b 790 FBA 9 f 030408 EFE 83 ebb 83548 DC 3007 BD

反向查找表(反向查找表)

在用戶的哈希列表中搜索哈希(apple)...:匹配[alice3,0bob0,charles8]

在用戶的哈希列表中搜索哈希(藍莓)...:匹配[usr10101,timmy,john91]

在用戶的哈希列表中搜索哈希(letmein)...:匹配[wilson10,dragonslayerX,joe1984]

在用戶的哈希列表中搜索哈希(s3cr3t)...:匹配[bruce19,knuth1337,john87]

在用戶的哈希列表中搜索哈希(z@29hjja)...:沒有用戶使用此密碼

這樣,攻擊者可以在不事先計算查詢表的情況下,對大量hash同時進行字典和蠻力攻擊。

首先,攻擊者會根據獲取的數據庫數據制作壹個用戶名和壹個對應的哈希表。然後哈希常用字典密碼,和這個表的哈希比較,就可以知道有哪些用戶使用過這個密碼。這種攻擊非常有效,因為通常很多用戶會使用同壹個密碼。

彩虹桌

彩虹表是壹種用空間交換時間的技術。這非常類似於表查找破解。只是它犧牲了壹些破解時間來達到存儲空間更小的目的。因為彩虹表使用的存儲空間更少,所以每單位空間可以存儲更多的hash。彩虹表已經可以破解任何8位長度的md5hash。彩虹表的具體原理可以參考/

在下壹章,我們將討論壹種叫做“加鹽”的技術。通過這種技術,hash無法被查表和彩虹表破解。

加鹽

hash(" hello ")= 2 cf 24 DBA 5 FB 0 a 30 e 26 e 83 B2 AC 5b 9 e 29 e 161e5c 1fa 7425 e 73043362938 b 9824

hash(" hello "+" qxluf 1 bgiadeqx ")= 9e 209040 c 863 f 84 a 31e 719795 b 2577523954739 Fe 5 ed 3 b 58 a 75 CFF 2127075 ed 1

hash(" hello "+" bv5 pehsmfv 11Cd ")= d 1 D3 EC 2e 6 f 20 FD 420d 50 e 2642992841d 8338 a 314 b8ea 157 C9 e 18477 aaef 226 ab

hash(" hello "+" yylmfy 6 iehjzmq ")= a 49670 C3 c 18 B9 e 079 b 9 CFAF 51634 f 563 DC 8 AE 3070 db 2 C4 a 8544305 df 1 b 60 f 007

查找表和彩虹表是有效的,因為每個密碼以相同的方式散列。如果兩個用戶使用相同的密碼,那麽他們的密碼哈希必須相同。我們可以通過隨機化每個哈希,將同壹個密碼哈希兩次並獲得不同的哈希來避免這種攻擊。

具體操作是給密碼加上前綴或後綴,然後哈希。這個直接的後綴或前綴就變成了“鹽”。就像上面舉的例子,通過加鹽,同樣的密碼每次都是完全不同的字符串。在檢查用戶輸入的密碼是否正確時,我們也需要這個salt,所以salt通常與hash壹起存儲在數據庫中,或者作為hash字符串的壹部分。

鹽不需要保密。只要鹽是隨機的,查表和彩虹表就無效。因為攻擊者無法提前知道鹽是什麽,所以沒有辦法提前計算出查詢表和彩虹表。如果每個用戶使用不同的salt,那麽反向表查找攻擊就無法成功。

在下壹節中,我們將介紹salt的壹些常見錯誤實現。

錯誤的做法:短鹽和鹽重復使用

最常見的錯誤實現是在多個哈希中使用了壹個salt,或者使用的salt非常短。

鹽再利用

無論salt是硬編碼在程序中還是壹次性隨機生成的,在每個密碼哈希中使用相同的salt都會使這種防禦方法失效。因為相同的密碼哈希兩次得到相同的結果。攻擊者可以利用反向查表進行字典和暴力攻擊。在散列字典中的每個密碼之前,只需添加這個固定的鹽。如果壹個流行的程序使用硬編碼的salt,那麽這個程序可能會有壹個查找表和彩虹表,以便快速破解hash。

用戶每次創建或修改密碼時都必須使用新的隨機salt。

淡鹽

如果salt的位數太短,攻擊者還可以預先為所有可能的salt制作壹個查找表。例如,3位ASCII字符的salt有95×95×95 = 857,375種可能性。看起來很多。如果每個salt生成壹個包含常用密碼的1MB的查找表,那麽857375個salt就是837GB。現在買個1TB的硬盤只要幾百塊錢。

同理,千萬不要把用戶名當鹽用。盡管每個用戶的用戶名可能不同,但是用戶名是可以預測的,而不是完全隨機的。攻擊者可以使用普通用戶名作為salt來制作查詢表,彩虹表來破解hash。

根據壹些經驗,規則是salt的大小要和hash函數的輸出壹致。比如SHA256的輸出是256位(32字節),salt的長度也應該是32字節的隨機數據。

錯誤的方式:雙重散列和怪異的散列函數

本節討論對哈希密碼的另壹個常見誤解:哈希算法的奇怪組合。人們可能會解決這樣壹個問題,即組合不同的哈希函數可以使數據更加安全。但實際上這種方法帶來的效果很小。相反,它可能會帶來壹些互操作性問題,甚至有時會使hash更加不安全。正如本文開頭提到的,妳千萬不要嘗試自己編寫哈希算法,而要使用專家設計的標準算法。有人認為使用多個哈希函數可以降低哈希計算的速度,從而增加破解的難度。有壹種更好的方法是通過減慢哈希計算速度來防禦攻擊,下面會詳細介紹。

這裏有壹些在互聯網上發現的奇怪的散列函數組合的例子。

md5(sha1(密碼))

md5(md5(鹽)+ md5(密碼))

sha1(sha1(密碼))

sha1(str_rot13(密碼+鹽))

md5(sha1(md5(md5(密碼)+ sha1(密碼))+ md5(密碼)))

不要用它們!

註:這部分內容其實是有爭議的!我收到了很多郵件說結合哈希函數有意義。因為如果攻擊者不知道我們用的是哪個函數,就不可能事先計算出彩虹表,結合哈希函數需要更多的計算時間。

攻擊者如果不知道哈希算法,就無法破解哈希。但是考慮到Kerckhoffs的原理,攻擊者通常可以訪問源代碼(尤其是自由軟件和開源軟件)。通過壹些目標系統的密碼-哈希對應來逆向算法並不是很難。

如果妳想使用壹個標準的“奇怪的”散列函數,比如HMAC,妳可以。但如果妳的目的是為了減緩hash的計算速度,可以閱讀後面討論的慢速hash函數部分。基於上面討論的因素,最好的方法是使用標準的、經過嚴格測試的散列算法。

哈希沖突(哈希沖突)

因為hash函數將任意數量的數據映射到壹個固定長度的字符串中,所以壹定會出現不同的輸入經過hash後變成相同字符串的情況。加密哈希函數旨在使這種沖突攻擊變得極其昂貴。但時不時地,密碼學家會找到壹種快速實現哈希碰撞的方法。最近的壹個例子是MD5,它的碰撞攻擊已經實現。

碰撞攻擊是尋找另壹個與原密碼不同但哈希相同的字符串。但是,即使是在相對較弱的哈希算法中,比如MD5,要實現碰撞攻擊也需要很大的計算能力,所以在實際使用中幾乎不可能意外發生哈希碰撞。實際上,使用salt MD5的密碼哈希與使用SHA256等其他算法壹樣安全。但如果可能的話,使用更安全的哈希函數是更好的選擇,比如SHA256、SHA512、RIPEMD、Whirlpool等。

正確的方法:如何正確地散列

本章詳細討論了如何正確散列密碼。第壹章是最基本的,這壹章的內容是必須的。下壹章將描述如何繼續增強安全性並使哈希破解變得極其困難。

基本:使用加鹽哈希

我們已經知道惡意黑客可以通過查表和彩虹表快速獲取hash對應的明文密碼,我們也知道使用隨機鹽可以解決這個問題。但是我們如何生成salt,如何在哈希過程中使用salt呢?

Salt應該由密碼安全的偽隨機數發生器(cspring)產生。CSPRNG與C語言中的rand()等普通偽隨機數生成器有很大不同。顧名思義,CSPRNG提供了壹個高標準的隨機數,完全不可預測。我們不希望我們的鹽是可預測的,所以我們必須使用CSPRNG。