原文:爲何要在密碼里加點「鹽」mysql
鹽(Salt)算法
在密碼學中,是指經過在密碼任意固定位置插入特定的字符串,讓散列後的結果和使用原始密碼的散列結果不相符,這種過程稱之爲「加鹽」。sql
以上這句話是維基百科上對於 Salt 的定義,可是僅憑這句話仍是很難理解什麼叫 Salt,以及它究竟起到什麼做用。數據庫
早期的軟件系統或者互聯網應用,數據庫中設計用戶表的時候,大體是這樣的結構:安全
mysql> desc User; +----------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+-------+ | UserName | varchar(50) | NO | | | | | PassWord | varchar(150) | NO | | | | +----------+--------------+------+-----+---------+-------+
數據存儲形式以下:加密
mysql> select * from User; +----------+----------+ | UserName | PassWord | +----------+----------+ | lichao | 123 | | akasuna | 456 | +----------+----------+
主要的關鍵字段就是這麼兩個,一個是登錄時的用戶名,對應的一個密碼,並且那個時候的用戶名是明文存儲的,若是你登錄時用戶名是 123,那麼數據庫裏存的就是 123。這種設計思路很是簡單,可是缺陷也很是明顯,數據庫一旦泄露,那麼全部用戶名和密碼都會泄露,後果很是嚴重。參見 《CSDN 詳解 600 萬用戶密碼泄露始末》。設計
爲了規避第一代密碼設計的缺陷,聰明的人在數據庫中不在存儲明文密碼,轉而存儲加密後的密碼,典型的加密算法是 MD5 和 SHA1,其數據表大體是這樣設計的:htm
mysql> desc User; +----------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+-------+ | UserName | varchar(50) | NO | | | | | PwdHash | char(32) | NO | | | | +----------+--------------+------+-----+---------+-------+
數據存儲形式以下:字符串
mysql> select * from User; +----------+----------------------------------+ | UserName | PwdHash | +----------+----------------------------------+ | lichao | 202cb962ac59075b964b07152d234b70 | | akasuna | 250cf8b51c773f3f8dc8b4be867a9a02 | +----------+----------------------------------+
假如你設置的密碼是 123,那麼數據庫中存儲的就是 202cb962ac59075b964b07152d234b70 或 40bd001563085fc35165329ea1ff5c5ecbdbbeef。當用戶登錄的時候,會把用戶輸入的密碼執行 MD5(或者 SHA1)後再和數據庫就行對比,判斷用戶身份是否合法,這種加密算法稱爲散列。get
嚴格地說,這種算法不能算是加密,由於理論上來講,它不能被解密。因此即便數據庫丟失了,可是因爲數據庫裏的密碼都是密文,根本沒法判斷用戶的原始密碼,因此後果也不算太嚴重。
原本第二代密碼設計方法已經很不錯了,只要你密碼設置得稍微複雜一點,就幾乎沒有被破解的可能性。可是若是你的密碼設置得不夠複雜,被破解出來的可能性仍是比較大的。
好事者收集經常使用的密碼,而後對他們執行 MD5 或者 SHA1,而後作成一個數據量很是龐大的數據字典,而後對泄露的數據庫中的密碼就行對比,若是你的原始密碼很不幸的被包含在這個數據字典中,那麼花不了多長時間就能把你的原始密碼匹配出來。這個數據字典很容易收集,CSDN 泄露的那 600w 個密碼,就是很好的原始素材。
因而,第三代密碼設計方法誕生,用戶表中多了一個字段:
mysql> desc User; +----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+-------+ | UserName | varchar(50) | NO | | | | | Salt | char(50) | NO | | | | | PwdHash | char(32) | NO | | | | +----------+-------------+------+-----+---------+-------+
數據存儲形式以下:
mysql> select * from User; +----------+----------------------------+----------------------------------+ | UserName | Salt | PwdHash | +----------+----------------------------+----------------------------------+ | lichao | 1ck12b13k1jmjxrg1h0129h2lj | 6c22ef52be70e11b6f3bcf0f672c96ce | | akasuna | 1h029kh2lj11jmjxrg13k1c12b | 7128f587d88d6686974d6ef57c193628 | +----------+----------------------------+----------------------------------+
Salt 能夠是任意字母、數字、或是字母或數字的組合,但必須是隨機產生的,每一個用戶的 Salt 都不同,用戶註冊的時候,數據庫中存入的不是明文密碼,也不是簡單的對明文密碼進行散列,而是 MD5( 明文密碼 + Salt),也就是說:
MD5('123' + '1ck12b13k1jmjxrg1h0129h2lj') = '6c22ef52be70e11b6f3bcf0f672c96ce' MD5('456' + '1h029kh2lj11jmjxrg13k1c12b') = '7128f587d88d6686974d6ef57c193628'
當用戶登錄的時候,一樣用這種算法就行驗證。
因爲加了 Salt,即使數據庫泄露了,可是因爲密碼都是加了 Salt 以後的散列,壞人們的數據字典已經沒法直接匹配,明文密碼被破解出來的機率也大大下降。
是否是加了 Salt 以後就絕對安全了呢?淡然沒有!壞人們仍是能夠他們數據字典中的密碼,加上咱們泄露數據庫中的 Salt,而後散列,而後再匹配。可是因爲咱們的 Salt 是隨機產生的,假如咱們的用戶數據表中有 30w 條數據,數據字典中有 600w 條數據,壞人們若是想要徹底覆蓋的壞,他們加上 Salt 後再散列的數據字典數據量就應該是 300000* 6000000 = 1800000000000,一萬八千億啊,幹壞事的成本過高了吧。可是若是隻是想破解某個用戶的密碼的話,只需爲這 600w 條數據加上 Salt,而後散列匹配。可見 Salt 雖然大大提升了安全係數,但也並不是絕對安全。
實際項目中,Salt 不必定要加在最前面或最後面,也能夠插在中間嘛,也能夠分開插入,也能夠倒序,程序設計時能夠靈活調整,均可以使破解的難度指數級增加。
PS,文中所謂第1、2、三代密碼的稱呼,是我本身 YY 的。