系列目錄:html
在不少網站的早期,甚至是如今仍然有一些網站,當你點擊忘記密碼功能時,你的郵箱會收到一封郵件,而後裏面赫然寫着你的密碼,不少普通用戶還會以爲慶幸,總算是找回來了,卻不知,這是多麼可怕地一件事,說明了網站是「幾乎是」明文存儲你的密碼,一旦數據用戶數據泄露或者被拖庫,那麼用戶密碼將赤裸裸的暴露了,想一想以前幾回互聯網密碼泄露事件。前端
那麼如何解決呢?程序員
爲了避免讓密碼明文存儲,咱們須要對密碼進行加密,這樣即便數據庫用戶密碼暴露,也是加密後的。可是如何讓加密後的數據難以解密呢?咱們如今比較流行的作法就是把密碼進行Hash存儲。算法
哈希算法將任意長度的二進制值映射爲較短的固定長度的二進制值,這個小的二進制值稱爲哈希值。哈希值是一段數據惟一且極其緊湊的數值表示形式. 典型的哈希算法包括 MD二、MD四、MD5 和 SHA-1數據庫
Hash算法是給消息生成摘要,那麼什麼是摘要呢?安全
舉個例子:服務器
好比你給你女友寫了一封郵件,確保沒被人改過,你能夠生成這樣一份摘要 「第50個字是我,第100個字是愛, 第998個字是你」,那麼你女友收到這個摘要,檢查一下你的郵件就能夠了。網絡
Hash算法有兩個很是主要的特徵:運維
所以,這個比較適合用來保存用戶密碼,由於不能反推出用戶密碼,Hash結果一致就證實原文一致,咱們來用Ruby代碼試一下上面的第二點 (MD5是一種經常使用的Hash算法)post
2.2.3 :003 > require 'digest/md5.so' => true 2.2.3 :004 > puts Digest::MD5.hexdigest('I love you') e4f58a805a6e1fd0f6bef58c86f9ceb3 => nil 2.2.3 :005 > puts Digest::MD5.hexdigest('I love you!') 690a8cda8894e37a6fff4d1790d53b33 => nil 2.2.3 :006 > puts Digest::MD5.hexdigest('I love you !') b2c63c3ca6019cff3bad64fcfa807361 => nil 2.2.3 :007 > puts Digest::MD5.hexdigest('I love you') e4f58a805a6e1fd0f6bef58c86f9ceb3 => nil 2.2.3 :008 >
那麼咱們在使用MD5保存密碼時候的驗證流程是什麼呢?
可是,若是你認爲就只是這樣密碼就不會被人知道,那麼就不對了,這只是比明文更安全,爲何?
由於,大部分人的密碼都很是簡單,當拿到MD5的密碼後,攻擊者也能夠經過比對的方式,好比你的密碼是4218
2.2.3 :008 > puts Digest::MD5.hexdigest('4218') d278df4919453195d221030324127a0e
那麼攻擊者能夠把1到4218個數字都MD5一下,而後和你密碼的MD5對比一下,就知道你原密碼是什麼了。
曾經個人密碼箱密碼忘了,我把鎖給撬了,後來我纔想起能夠用窮舉法,最多就999次不就打開了?那麼問題來了,你的密碼箱還安全嗎?
除了窮舉法外,因爲以前的密碼泄露,那麼攻擊者們,手上都有大量的彩虹表,好比"I love you",生日等等,這個表保存了這些原值以及MD5後的值,那麼使用時直接從已有庫裏就能夠查出來對應的密碼。
那麼,因爲簡單的對密碼進行Hash算法不夠安全,那麼咱們就能夠對密碼加Salt,好比密碼是"I love you", 雖然彩虹表裏有這條數據,可是若是加上"安紅我愛你",這樣MD5結果就大不同.
jacks-MacBook-Air:~ jack$ irb 2.2.3 :001 > require 'digest/md5.so' => true 2.2.3 :002 > puts Digest::MD5.hexdigest('I love you') e4f58a805a6e1fd0f6bef58c86f9ceb3 => nil 2.2.3 :003 > puts Digest::MD5.hexdigest('I love you安紅我愛你') b10d890bf46b1a045eb99af5d43c7b13 => nil 2.2.3 :004 > puts Digest::MD5.hexdigest('I dont love you') c82294c9a7b6e4a372ad25ed4d6011c9 => nil 2.2.3 :005 > puts Digest::MD5.hexdigest('I dont love you安紅我愛你') dce67bcdfdf007445dd4a2c2dc3d29c1 => nil 2.2.3 :006 >
如此一來,由於攻擊者很難猜到「安紅我愛你」,那麼天然彩虹表裏是沒有的,固然我建議你在實際項目中不要使用"安紅我愛你",你應該使用一個連你本身都猜不到的較長的字符串。
實際上,加鹽並不能100%保證安全,假若有人泄露了你的Salt呢?實際上經過反編譯程序很容易能夠拿到這個,因爲WEB程序通常放在WEB服務器上,那麼就須要保證服務器不被攻擊,固然這個是運維人員去操心。
爲了讓加鹽更安全,通常狀況下咱們可使用一個「鹽+鹽」,也就是爲每一個用戶保存一個"Salt", 而後再使用全局的鹽,咱們能夠對用戶的鹽使用本身的加密算法。那麼代碼就以下:
if MD5(userInputPpassword+globalsalt+usersalt)===user.databasePassword) { login success }
因爲這個是寫給程序員,固然是說在前端用戶註冊時密碼應該如何設置,很簡單,咱們要求用戶必須輸入強密碼!可是,我知道不少用戶以爲很煩,這樣你就失掉了一個用戶,但咱們須要作一個適當的折中,好比至少有一個大寫字母,小寫字母和數字的組合。
咱們來看看解決了以前文章下面例子的什麼問題。
假如,明明和麗麗相互不認識,明明想給麗麗寫一封情書,讓隔壁老王送去
經過了解hash算法,"明明" 就有辦法讓麗麗知道信的內容沒有修改,他能夠對郵件進行Hash生成郵件的摘要,而後讓"隔壁的李叔叔"把摘要送給麗麗,麗麗拿到郵件的摘要後,把郵件內容也Hash一下,而後把結果和"隔壁的李叔叔"給的摘要對比一下,而後經過比較結果就知道郵件有沒有被"隔壁的王叔叔"更改過了。