前兩天準備登錄某網站的時候,在嘗試了幾回經常使用密碼失敗後,我點擊了「忘記密碼」,嫺熟地填入手機號碼,隨即就收到了一條來自陌生號碼的短信,裏面包含着一個六個數字串,我將這個數字串填入網站提供的輸入框,就進入了密碼重置流程。
程序員
這裏有一點細節,值得咱們注意,爲何我忘記了密碼,你不直接把原密碼返回給我?而是給我一個不相關的口令來重置密碼?算法
前段時間,華住(某大型連鎖酒店)再次發生脫庫事件。因爲內部程序員失誤,將數據庫密碼公開於Github上,讓人拿走了數億用戶的開戶記錄和他們的登錄信息(包括密碼)。假如這些密碼用明文存儲,那不法分子盜取數據庫後,拿到明文密碼,就能夠垂手可得的拿郵箱和密碼去嘗試登錄你的各類社交網站,甚至各類金融賬戶。要知道有不少人其實對帳戶安全不夠重視,金融帳戶和社交帳號都使用同一個密碼。在如此數量級下(上億)的賬戶密碼泄露,對於互聯網安全將是一場巨大的浩劫。shell
如此看來,服務器是不會明文存儲你的用戶密碼的。這也就能解釋,爲何不乾脆直接將原密碼返回給你了。由於就連他們也不知道。數據庫
那麼問題來了,在數據庫存儲的究竟是什麼?它應該是被某種算法加密過的密文,而且沒法進行反向破解,保證了被***拿到了也能保證數據的相對安全。而這個算法,就是咱們接下來要介紹對哈希算法。安全
哈希(Hash)算法,因爲其不可反向破解的特性被普遍用於私密信息的保護和校驗。服務器
哈希算法是一個比較泛的概念,他的具體實現有許多種,你們所熟知的有 MD5,SHA256等。微信
如今拿 MD5來舉例,MD5消息摘要算法(英語:MD5 Message-Digest Algorithm),一種被普遍使用的密碼散列函數,能夠產生出一個128位(16字節)的散列值(hash value)。網絡
可是人類實在看不慣二進制,因此128位的二進制一般會表示成32位的十六進制(由0-9,a-f組成),他們是等價的。ide
說了那麼多,這個散列值到底長啥樣呢。函數
在 Python 中
import hashlib
m1 = hashlib.md5()
m1.update("hello")
print(m1.hexdigest())
# 5d41402abc4b2a76b9719d911017c592
用 shell 就更簡單了
echo -n hello | md5sum
# 5d41402abc4b2a76b9719d911017c592 -
有很多人會將 哈希(Hash) 和 加密(Encrypt)混淆起來,其實它們是不同的:
哈希:將目標文本轉換成具備相同長度的、不可逆的字符串,也叫消息摘要,是一對多的映射關係(即多個明文可能對應同一個哈希值)。
加密:將目標文本轉換成具備不一樣長度的、可逆的密文,是一對一的映射關係(即一個密文只能對應一個明文)
因爲哈希算法是一對多的映射,因此不一樣的輸入是有可能獲得了同一個哈希值,這時候就發生了"哈希碰撞"(collision)。
哈希碰撞雖然發生機率小,可是一旦發生,就會產生嚴重的安全問題:
案例一
不少網絡服務會使用哈希函數,產生一個 token 用於標識用戶的身份和權限。
若是兩個不一樣的用戶,獲得了一樣的 token,就發生了哈希碰撞。服務器將把這兩個用戶視爲同一我的,這意味着,用戶 B 能夠讀取和更改用戶 A 的信息,這無疑帶來了很大的安全隱患。
案例二
咱們都用過網絡支付工具,假如我如今從 A 賬戶轉給賬戶 B 1000塊錢,交易信息在網絡中進行傳輸,有可能被***給截持並篡改咱們的數據,將目標賬戶改爲***本身的賬戶。如此一來,咱們的金錢就被竊取了。
若是使用哈希算法,就能夠在客戶端處,將轉帳的信息進行處理,處理方法是,將要加密的數據加上一個約定好的字符串一塊兒進行哈希,生成一個信息摘要。
假如在網絡傳輸過程當中不幸被***修改了目標賬戶和轉賬金額,等到了支付平臺的服務器端,會將傳輸過來的信息和以前約定好的字符串再次進行哈希。而後和以前那個哈希進行比對,因爲以前的數據已經被篡改了,因此驗證不經過,轉賬失敗。從而保證了咱們的資金安全。
前面講到了許多哈希在實際生活中的應用,能夠發現,哈希被普遍的應用在安全領域。那哈希真的沒有辦法破解嗎?
固然有,這裏舉三個常見的例子。
暴力窮舉法,就是簡單粗暴的枚舉出全部的原文,並計算其哈希值,而後將計算結果與目標哈希值一一比對。因爲原文的可能性有無數多種,因此這種方法時間複雜度高得離奇,極不可取。須要大量的計算,所以破解速度很是慢,以14位字母和數字的組合密碼爲例,共有1.24×10^25種可能,即便電腦每秒鐘能進行10億次運算,也須要4億年才能破解。
就算有一天,真找到一個和目標哈希值相等的原文,這個原文也不必定是答案,由於哈希衝突的存在,多個原文是有可能有着同一個哈希值。
反思暴力枚舉法,它其實作了太多無用的計算。通常人的密碼都會取一些有特殊意義的字符,好比生日,名字縮寫等。有人就會把這些經常使用的高頻率的密碼組合,試先計算並存儲起來。等到要用的時候,直接到數據庫裏查詢對應的哈希值就好了。
若是說暴力枚舉法,是時間換空間,那字典法就是空間換時間。
須要海量的磁盤空間來儲存數據,仍以14位字母和數字的組合密碼爲例,生成的密碼32位哈希串的對照表將佔用2.64 * 10^14 TB
的存儲空間。如何增長密碼長度或添加符號,須要的時間或磁盤空間將更加不可思議,顯然這兩種方法是難以讓人滿意的。
(62^14*192)/8/1024/1024/1024/1024=2.64 * 10^14 (GB)
暴力枚舉和字典法,都只適用於長度較短,組合簡單的密碼。
接下來爲你們介紹一種高效的密碼***方法:彩虹表。它能夠用於複雜一點的密碼。
彩虹表實質上仍是屬於字典破解的一種,不過再也不是簡單的明文—密碼的對應,爲了節省字典存儲空間,彩虹表省去了能經過計算得出的數據,達到這點的關鍵在於設計出一個函數族Rk(k=一、二、三、4……)將hash密文空間映射回明文的字符空間。
具體內容可點擊查看:漫畫:如何破解MD5算法?
彩虹表的存儲空間是字典法的 k 分之一,代價是運算次數至少是原來的 k 倍。
彩虹表確實像它的名字同樣美好,至少***眼裏是這樣。下表是7位之內密碼在不一樣字符集下構造出的彩虹表的狀況,彩虹表中哈希鏈的長度和個數隨着字符集的增加而增加,彩虹表的大小和生成時間也隨之成倍增長。7位數字組合在彩虹表面前簡直就是秒破,即便最複雜的7位密碼不到一個小時就能破解,若是採用普通的暴力***,破解時間可能須要三週。
這篇文章,寫得比較通俗易懂,其中借鑑了網上一些不錯的文章,算是一篇科普文,想要深刻了解,你還須要本身作更多的研究與思考。若是有寫得不對的地方歡迎你們微信我指正!
另,感謝閱讀,若是文章對你有幫助,但願你能夠分享至朋友圈,讓更多的人看到。