聽說,有些網站明文存儲用戶密碼?

前段時間爆出 Facebook 明文存儲用戶密碼,多達 6 億用戶,而它的用戶總數是 27 億,佔比 22 % 。

看到這個消息,是不是很震驚?

無獨有偶,之前有聽過很多銀行系統的密碼也是明文(真假沒有驗證)。

在讀書時,忘記學校網站密碼後,直接打電話給 IT 人員,IT 人員讓我說出可能的密碼,然後他會告訴我是否正確。那時候我懷疑密碼是明文存儲的,雖然也沒能驗證。爲什麼懷疑是明文,怎麼可能要求每個 IT 人員都知道怎麼對密碼進行一定的變換,然後和存儲的密碼進行比較呢?(如果有相應的工具那麼另說)

明文存儲密碼存在泄露的風險,也存在撞庫的風險。什麼是撞庫?撞庫就是你在好幾家網站上共用一個密碼,一家的數據庫泄露,你在其他網站的密碼信息也就被泄露了。關於這種情況,你會說,每個網站密碼用不一樣的不就好了?可是,有那麼多網站,那麼多密碼你記得過來嗎?

我們知道明文存儲密碼是不安全的,加密存儲密碼是安全的。

但是,加密存儲密碼也不一定安全,隨着技術的進步,之前的加密算法的安全性大大降低,很容易被破解,於是新的加密算法不斷被提出。在這個過程中,有如下幾種密碼的存儲方式。

 

方法 1:一次 HASH 操作

很早的方法是對密碼進行 HASH 操作(如 MD5, SHA - 1,SHA - 256 算法)。HASH(哈希)也即散列:把任意長度的輸入通過散列算法變換成固定長度的輸出,該輸出就是散列值。簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要。

以 MD5 爲例,講述密碼存儲過程。服務端將密碼進行 MD5 操作後得到的值存儲到數據庫中。客戶端將明文密碼進行 MD5 操作,然後將值發送給服務端,服務端將收到的值和數據庫中存儲的值相比較就可以知道傳入的密碼是否正確。這種情況下,服務端也不知道真實的密碼,所以密碼是找不回的,只能重置。

由於 MD5 是單向的、不可逆的,所以這種方式流行了很長時間。

MD5 的原理是對於特定的輸入產生特定的輸出。這既是它的工作原理,也可以用於進行破解:可以進行數字、字母的組合來確定真實的密碼。最簡單的是暴力破解,就是一直嘗試,直至成功。但是服務端一般會限制嘗試的次數,也即失敗一定次數後,鎖定 IP 一段時間。有些網站並不會告訴你是用戶名錯誤還是密碼錯誤,防止你進行有針對性的窮舉,只會告訴你密碼或者用戶名錯誤。

暴力破解的升級版是查表破解,也即先生成大量的 HASH 值並進行存儲。需要破解的時候直接進行查表匹配,只要匹配上,就可以獲得明文密碼。這種方式是用空間換時間,也規避了服務器限制登錄失敗次數的這一限制。如果將生成的 HASH 值存儲到文件中,可以被網絡用戶共享,可以被更多人使用。

更先進的方法是 Rainbow table(彩虹表),原理和查表破解有些相似,只不過以犧牲時間來達到更小的存儲空間,也即以時間換空間。進行匹配時耗時比較久,但是 HASH 值存儲所佔的空間比較小。

Rainbow table 對於簡單密碼的破解很有效,1.4 G 的彩虹表可以在 13.6 s 內破解 99.9% 的數字字母混合型的 Windows 密碼。如果是 6 位純數字密碼,只有 10^6 種組合(譬如銀行卡密碼),只有 1 百萬種可能性。如果是 6 位的數字和大小寫字母的組合,共有(10 + 26 * 2) ^ 6 ,大約是 568 億種可能性。如果是 8 位的數字和大小寫字母的組合,共有 218.34 萬億種可能性。如果將標點符號也包含進來,那麼可能性就更多了。所以,現在很多網站要求用戶設置的密碼長度不低於 8 位,需要包含數字、字母(區分大小寫)、標點符號等,將破解難度增大。

雖然密碼的強度增加了,但是面對日益增長的硬盤大小及計算能力(超核、GPU、特定 HASH 硬件),此種方式也不那麼可靠了。

一次 MD5 的方式雖然可以被破解,但這並不是 MD5 最大的問題,其致命的問題是 MD5 算法並不可靠:之前人們以爲對於不同的輸入,輸出不同;後來被證明,對於不同的輸入,輸出可能相同。

針對一次 HASH 的不足,人們提出了 HASH + Salt(鹽值)的操作。

 

方法 2:HASH + Salt

HASH + Salt 的操作也稱爲兩次 HASH,其原理是:第一次 HASH 操作進行身份的初次鑑權,網站會返回一個隨機數(Salt,鹽值),客戶端通過服務器返回的隨機數以及協商好的規則進行第二次 HASH 操作,將操作結果發送給服務器,服務器也通過相同的方法進行操作,如果兩次結果相同,那麼就鑑權成功。

此種方式下,服務器也不存儲明文密碼,存儲的是密碼第一次 HASH 後的結果。即使該值被泄露,也不會泄露明文密碼。

爲什麼兩次 HASH 會比較安全呢?一是其引入了隨機數;二是第二次 HASH 的規則可以自定義。隨機數使得暴力破解及 Rainbow table 方式破解的難度增大很多,但也並不是不可能(想想內存及計算能力的飛速發展)。第二次 HASH 的規則可以自定義,也增大了破解的難度。

仔細想一下,鹽值的產生及維護也有一定的技巧。

鹽值應該滿足如下幾個特點:

  1. 鹽值的隨機性要比較好,不能使用 rand 類的函數,應該使用CSPRNG(Windows 下的 CryptGenRandom 函數及 Linux 下讀取 /dev/urandom 文件)

  2. 鹽值不應該太短

  3. 鹽值應該唯一:不同用戶不同鹽值

  4. 鹽值不應該是一些特殊字符串,譬如用戶名、手機號等

稍微想一想,鹽值得存儲也有很多學問,不能和密碼 HASH 後的值存儲在一起。

 

方法 3:對稱加密算法

採用 AES 等對稱加密算法對密碼進行加密,然後對加密後的密文進行存儲。

此種方式下的密鑰存儲及管理也是不小的難題。是爲每個用戶產生一個密鑰,還是爲一定數量的用戶產生一個密鑰?如果每個用戶一個密鑰,那麼管理難度較大。如果一定數量用戶一個密鑰,那麼安全性又不高。

對稱加密算法加密後的密文可以進行解密得到明文,如果密鑰泄露,那麼明文密碼也存在泄露的可能性。

此種方式下,客戶端需要對明文密碼進行加密(對於 HTTPS,不需要考慮此種情況)。那麼,就會涉及密鑰傳輸的問題。密鑰的傳輸主要有兩種方法:

  1.  公鑰加密方法:如 RSA 算法 + AES 算法

  2.  密鑰交換算法:如 DH 算法

公鑰加密傳輸密鑰的步驟如下:

  1. 客戶端獲取服務端的公鑰(RSA 算法產生),用服務端的公鑰加密對稱加密算法(AES 算法)的密鑰(該密鑰用於加密用戶密碼),然後將結果發送給服務端

  2. 服務端用自己的私鑰(RSA 算法產生)解密出對稱加密算法的密鑰,然後用該密鑰解密出用戶密碼

  3. 服務端用保存的密鑰加密上一步得到的明文密碼,然後和數據庫中存儲的密文密碼進行比較(或者解密出數據庫中的明文密碼,和解密出的用戶明文密碼進行比較),如果相同,那麼驗證通過;否則,驗證失敗

上述過程中,服務端需要維護密文密碼、密鑰、公鑰文件及私鑰文件,對於大量用戶的場景,難度也不小。

當然,也可以通過密鑰交換算法傳輸加密明文密碼時需要的密鑰,如 DH 算法,感興趣的可以去研究一下。

 

方法 4:密碼 HASH 算法

常用的密碼 HASH 算法有 PBKDF2、 bcrypt(blowfish)、scrrpt。雖然這裏稱之爲密碼 HASH,但是不同於之前說的 MD5 等算法。密碼 HASH 算法的基本思想是提高暴力破解的時間成本或者空間成本。

PBKDF2(Password-Based Key Derivation Function 2)簡單而言就是將 Salted hash 進行多次重複計算,這個次數是可選擇的,可以明確指定 HASH 次數,指定的次數越多,暴力破解的成本也就越多。

Bcrypt 是專門爲密碼存儲而設計的算法,基於 Blowfish 加密算法變形而來。Bcrypt 最大的好處是有一個參數(work factor),可用於調整計算強度,而且 work factor 是包括在輸出的摘要中的。隨着攻擊者計算能力的提高,使用者可以逐步增大 work factor,而且不會影響已有用戶的登陸。

Scrypt 是由著名的 FreeBSD 黑客 Colin Percival 爲他的備份服務  Tarsnap 開發的。Scrypt 不僅計算所需時間長,而且佔用的內存也多,使得並行計算多個摘要異常困難,因此利用 Rainbow table 進行暴力攻擊更加困難。

 

在實際的使用場景中,上述方案都有其應用場景。對安全的認知、資源、技術等因素往往會影響對方案的選擇,上述方案也可以相互結合,以減小密碼泄露的可能性。

對用戶密碼進行加密存儲是一個難度不小的挑戰,所以,一些網站明文存儲密碼也就不難理解了。在設置密碼時,最好增大密碼強度,多個網站儘量不要使用相同的密碼,定期更換密碼,以減小密碼泄露的可能性。

掃描二維碼,關注“清遠的夢囈”,手機端查看文章

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章