歡迎光臨
每天分享高質量文章

漫話:如何給女朋友解釋為什麼12306會用戶信息泄露(上)——密碼篇

某天下午,我正在公司愉快的擼代碼,突然來了一個電話。原來是女朋友打來的。

掛斷電話後,我趕緊登錄12306改掉了我的密碼,還好我各個網站的密碼不一樣,這樣就能很好的避免被撞庫了。

下班後,回到家中,女朋友第一時間過來找我,一定要我給他解釋一下12306的資料泄露背後的知識。

明文密碼

明文密碼就是直接可以看懂的,比如123456admin等等,而不是經過加密顯示出****的內容,這種叫做暗碼。比如abc代表123,如果告訴你abc而不告訴你解碼規則,你就不能翻譯出真正的密碼123

很多網站都有註冊登錄功能,對於用戶在註冊的時候,填寫的用戶名和密碼,如果不經過任何處理直接儲存到資料庫中,這種情況下,儲存的就是用戶的明文密碼。

這樣直接把用戶的明文密碼儲存下來,對於程式開發來說是很方便的。用戶在登錄的時候直接到資料庫中進行賬號密碼匹配就可以了。但是,同時也埋下了很大的隱患,一旦資料庫信息泄露,那麼黑客就可以拿到所有用戶的用戶名和密碼。

舉個例子,比如用戶的明文密碼是helloworld,加密後的密文是xxeerrqq

用戶註冊:

helloworld -> 加密 -> xxeerrqq -> 儲存xxeerrqq到資料庫中

用戶登錄

helloworld -> 加密 -> xxeerrqq -> 使用xxeerrqq到資料庫中匹配密碼

密碼加密技術經過很多年的發展,已經有了很多成熟的方案,這裡就簡單介紹幾個。

對稱加密

對稱加密,指的是需要對加密和解密使用相同密鑰的加密演算法。

最簡單的對稱加密演算法就是通過ASCII碼的變化進行密碼儲存,比如把abcde轉換成bcdef,其加密演算法就是把ASCII碼增加1 。

這種加密演算法,有一個特點,就是可以根據加密後得到的密文,再根據密鑰還原出明文。

但是,這種演算法已經很少有網站在用了,雖然現在有很多方法可以把密鑰單獨儲存,但是,既然黑客可以破解網站拿到用戶的密文,就有可能也能獲取到密鑰。

在對稱加密演算法中常用的演算法有:DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK等。

單向Hash演算法

單向散列演算法,又稱hash函式,就是把任意長的輸入訊息串變化成固定長的輸出串的一種函式。一般用於產生訊息摘要,密鑰加密等。

單向Hash演算法是一種無法通過計算還原出原始密碼,而且實現比較簡單的演算法。

很多互聯網公司都採用這種方式儲存用戶密碼,曾經這種方式也是比較安全的方式。

常見散列函式(Hash函式)有: MD5(Message Digest Algorithm 5)、 SHA(Secure Hash Algorithm)、 MAC(Message Authentication Code)、 CRC(Cyclic Redundancy Check)

彩虹表

彩虹表(rainbow table)是一個用於加密散列函式逆運算的預先計算好的表,常用於破解加密過的密碼散列。 查找表常常用於包含有限字符固定長度純文本密碼的加密。這是以空間換時間的典型實踐,在每一次嘗試都計算的暴力破解中使用更少的計算能力和更多的儲存空間,但卻比簡單的每個輸入一條散列的翻查表使用更少的儲存空間和更多的計算性能。

通常情況下,當欄位經過散列處理(如MD5),會生成一段散列值,而散列後的值一般是無法通過特定演算法得到原始欄位的。但是某些情況,比如一個大型的彩虹表,通過在表中搜索該MD5值,很有可能在極短的時間內找到該散列值對應的真實欄位內容。

加鹽Hash演算法

鹽(Salt),在密碼學中,是指在散列之前將散列內容(例如:密碼)的任意固定位置插入特定的字串。這個在散列中加入字串的方式稱為“加鹽”。其作用是讓加鹽後的散列結果和沒有加鹽的結果不相同,在不同的應用情景中,這個處理可以增加額外的安全性。

加鹽後的散列值,可以極大的降低由於用戶資料被盜而帶來的密碼泄漏風險,即使通過彩虹表尋找到了散列後的數值所對應的原始內容,但是由於經過了加鹽,插入的字串擾亂了真正的密碼,使得獲得真實密碼的概率大大降低。

對於加了“固定鹽”的Hash演算法,需要保護“鹽”不能泄露,這就會遇到“保護對稱密鑰”一樣的問題,一旦“鹽”泄露,根據“鹽”重新建立彩虹表可以進行破解。

PBKDF2演算法

PBKDF2演算法,即Password-Based Key Derivation Function 2。PBKDF2簡單而言就是將加鹽Hash進行多次重覆計算,這個次數是可選擇的。

該演算法原理大致相當於在Hash演算法基礎上增加隨機鹽,併進行多次Hash運算,隨機鹽使得彩虹表的建表難度大幅增加,而多次Hash也使得建表和破解的難度都大幅增加。

如果計算一次所需要的時間是1微秒,那麼計算1百萬次就需要1秒鐘。假如攻擊一個密碼所需的彩虹表有1千萬條,建立所對應的彩虹表所需要的時間就是115天。這個代價足以讓大部分的攻擊者忘而生畏。

美國政府機構已經將這個方法標準化,並且用於一些政府和軍方的系統。 這個方案最大的優點是標準化,實現容易同時採用了久經考驗的SHA演算法。

還有很多演算法也可以有效抵禦彩虹表,常見的有bcrypt、scrypt等。

bcrypt

bcrypt是專門為密碼儲存而設計的演算法,基於Blowfish加密演算法變形而來,由Niels Provos和David Mazières發表於1999年的USENIX。

實現中bcrypt會使用一個加鹽的流程以防禦彩虹表攻擊,同時bcrypt還是適應性函式,它可以藉由增加迭代之次數來抵禦日益增進的計算機運算能力透過暴力法破解。

由bcrypt加密的檔案可在所有支持的操作系統和處理器上進行轉移。它的口令必須是8至56個字符,並將在內部被轉化為448位的密鑰。然而,所提供的所有字符都具有十分重要的意義。密碼越強大,您的資料就越安全。

bcrypt經過了很多安全專家的仔細分析,使用在以安全著稱的OpenBSD中,一般認為它比PBKDF2更能承受隨著計算能力加強而帶來的風險。bcrypt也有廣泛的函式庫支持,因此建議使用這種方式儲存密碼。

Java中使用bcrypt

可以在官網(http://www.mindrot.org/projects/jBCrypt/ )獲取該演算法的原始碼。在Java中,可以直接使用以下方式進行加密:

public static void main(String[] args) throws NoSuchAlgorithmException

{
    String  originalPassword = "漫話編程";
    String generatedSecuredPasswordHash = BCrypt.hashpw(originalPassword, BCrypt.gensalt(12));
    System.out.println(generatedSecuredPasswordHash);

    boolean matched = BCrypt.checkpw(originalPassword, generatedSecuredPasswordHash);

    System.out.println(matched);

}

scrypt

scrypt是由著名的FreeBSD黑客 Colin Percival為他的備份服務 Tarsnap開發的。

設計時考慮到大規模的客制硬體攻擊而刻意設計需要大量記憶體運算。scrypt需要使用大量記憶體的原因來自於產生大量偽隨機性(英語:pseudorandom)資料作為演算法計算的基礎。一旦這些資料被產生後,演算法將會以偽隨機性的順序讀取這些資料產生結果。因此最直接的實做方式將會需要大量記憶體將這些資料儲存在記憶體內供演算法計算。

scrypt不僅計算所需時間長,而且占用的記憶體也多,使得並行計算多個摘要異常困難,因此利用彩虹表進行暴力攻擊更加困難。scrypt沒有在生產環境中大規模應用,並且缺乏仔細的審察和廣泛的函式庫支持。但是,scrypt在演算法層面只要沒有破綻,它的安全性應該高於PBKDF2和bcrypt。

Java中使用scrypt

有一個Java實現的scrypt工具類庫(https://github.com/wg/scrypt )可以直接使用。用法也比較簡單:

public static void main(String[] args{

    String originalPassword = "漫話編程";

    String generatedSecuredPasswordHash = SCryptUtil.scrypt(originalPassword, 161616);
    System.out.println(generatedSecuredPasswordHash);

    boolean matched = SCryptUtil.check("漫話編程", generatedSecuredPasswordHash);
    System.out.println(matched);

    matched = SCryptUtil.check("漫畫編程", generatedSecuredPasswordHash);
    System.out.println(matched);
}

    赞(0)

    分享創造快樂