某天下午,我正在公司愉快的擼程式碼,突然來了一個電話。原來是女朋友打來的。
結束通話電話後,我趕緊登入12306改掉了我的密碼,還好我各個網站的密碼不一樣,這樣就能很好的避免被撞庫了。
下班後,回到家中,女朋友第一時間過來找我,一定要我給他解釋一下12306的資料洩露背後的知識。
明文密碼
明文密碼就是直接可以看懂的,比如123456
,admin
等等,而不是經過加密顯示出****
的內容,這種叫做暗碼。比如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)是一個用於加密雜湊函式逆運算的預先計算好的表,常用於破解加密過的密碼雜湊。 查詢表常常用於包含有限字元固定長度純文字密碼的加密。這是以空間換時間的典型實踐,在每一次嘗試都計算的暴力破解中使用更少的計算能力和更多的儲存空間,但卻比簡單的每個輸入一條雜湊的翻查表使用更少的儲存空間和更多的計算效能。

加鹽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, 16, 16, 16);
System.out.println(generatedSecuredPasswordHash);
boolean matched = SCryptUtil.check("漫話程式設計", generatedSecuredPasswordHash);
System.out.println(matched);
matched = SCryptUtil.check("漫畫程式設計", generatedSecuredPasswordHash);
System.out.println(matched);
}複製程式碼