涉及身份驗證的系統都須要存儲用戶的認證信息,經常使用的用戶認證方式主要爲用戶名和密碼的方式,爲了安全起見,用戶輸入的密碼須要保存爲密文形式,可採用已公開的不可逆的hash加密算法,好比SHA256, SHA512, SHA3等,對於同一密碼,同一加密算法會產生相同的hash值,這樣,當用戶進行身份驗證時,也可對用戶輸入的明文密碼應用相同的hash加密算法,得出一個hash值,而後使用該hash值和以前存儲好的密文值進行對照,若是兩個值相同,則密碼認證成功,不然密碼認證失敗。算法
因爲密碼是由用戶設定的,在實際應用中,用戶設置的密碼複雜度可能不夠高,同時不一樣的用戶極有可能會使用相同的密碼,那麼這些用戶對應的密文也會相同,這樣,當存儲用戶密碼的數據庫泄露後,攻擊者會很容易便能找到相同密碼的用戶,從而也下降了破解密碼的難度,所以,在對用戶密碼進行加密時,須要考慮對密碼進行掩飾,即便是相同的密碼,也應該要保存爲不一樣的密文,即便用戶輸入的是弱密碼,也須要考慮進行加強,從而增長密碼被攻破的難度,而使用帶鹽的加密hash值便能知足該需求。數據庫
輸入: 密碼字符串passWord安全
輸出:鹽值 salt 、密碼密文passWordHashdom
函數:加密hash函數ide
其中:「鹽值 salt」是在加密過程當中生成的隨機字符串;函數
能夠將salt放到passWord前面做爲前綴或放到passWord後面做爲後綴獲得新的字符串PS,即,PS = password和salt的組合串;加密
密碼密文passWordHash = Hash加密函數(PS );spa
將用戶名、密碼密文passWordHash和鹽值salt一塊兒保存到數據庫中。.net
輸入: 密碼字符串passWordCur3d
輸出:密碼校驗是否成功
處理: 1)、取出當前用戶密碼加密時使用的鹽值salt
2)、獲得本次輸入的密碼passWordCur和鹽值salt的組合字符串PS
3)、得出本次輸入密碼的密文passWordHashCur= Hash加密函數(PS );
4)、比較passWordHashCur和用戶最初設置的密碼密文passWordHash是否一致,若是一致,則校驗成功,不然校驗失敗。
經常使用的密碼攻擊方式有字典攻擊、暴力破解、查表法、反向查表法、彩虹表等。
對字典攻擊和暴力破解,攻擊者均採用逐密碼嘗試的方式,目前沒有很好的手段來阻止字典攻擊和暴力破解攻擊,只能是想辦法讓這兩種攻擊方式變得相對低效一些,而相同的密碼產生不一樣的hash值便能讓攻擊者針對每個hash值都須要從頭進行嘗試,從而使攻擊變得更加低效。
對查表法、反向查表法和彩虹表攻擊方式,攻擊者須要提早準備好包含密碼和密碼hash值的密碼錶,而後根據該表和用戶密碼數據庫進行批量匹配,從而達到攻破密碼的目的;而若是咱們在加密時,給每一個密碼附加了不一樣的隨機值,這樣每一個密碼對應的hash值也會不一樣,這樣攻擊者在準備密碼錶時,就必需要將最基本的密碼和用戶密碼數據庫中的鹽值進行笛卡爾積後再計算hash值,鹽值越多,用戶須要準備的表量越大,這樣對於攻擊而言,就變得有些得不償失了。
加鹽的目的是爲了增長攻擊者破解的難度,那麼在加鹽的時候要注意如下幾點,不然加鹽的意義也不會太大。
1)、鹽值不能過短;若是鹽值只有少數兩三位甚至一兩位的話,攻擊者徹底能夠窮舉全部可能的鹽值;關於鹽值長度的一個經驗值是長度至少要和hash加密函數的返回值長度保持一致。
2)、鹽值不能固定;若是系統使用了固定的鹽值,那麼和不加鹽至關因而一回事了,攻擊者徹底可使用該固定的鹽值提早準備密碼錶;另外,相同密碼對應的hash值仍然是同樣的,仍然沒法對密碼相同這一事實進行掩飾。
3)、不要使用能提早預知的值做爲鹽值;若是鹽值能提早得知或提早推斷出,攻擊者也徹底能夠根據提早預知的鹽值準備密碼錶,從而對破解的難度也增長不了多少。
4)、每一次修改密碼從新計算hash值時,要從新生成新的鹽值,不要使用上次密碼對應的鹽值;由於若是用戶密碼泄露以後,鹽值相應的也就泄露了,用戶修改密碼時,若是還沿用原來的鹽值,攻擊者也仍然能夠根據上次的鹽值提早準備密碼錶,從而使攻破可能性變得更高了。
/// <summary> /// 對用戶輸入的密碼進行加密 /// </summary> /// <param name="passWord">輸入的明文密碼</param> /// <param name="salt">加密過程當中產生的鹽值</param> /// <returns>加密後的密碼值</returns> private static string GetHashSha256AndSalt(string passWord,out string salt) { //首先生成隨機加密鹽 RandomNumberGenerator saltNumber = new RNGCryptoServiceProvider(); byte[] s = new byte[256]; saltNumber.GetBytes(s); salt = Convert.ToBase64String(s); //將鹽值轉化爲字符串 return GetHashSha256(passWord, salt);//針對鹽值和密碼一塊兒應用hash加密函數,獲得明文密碼 } /// <summary> /// 對用戶輸入的密碼採用指定的鹽值進行加密 /// </summary> /// <param name="passWord">輸入的明文密碼</param> /// <param name="salt">指定的鹽值</param> /// <returns>加密後的密碼值</returns> private static string GetHashSha256(string passWord, string salt) { byte[] bytes = Encoding.Unicode.GetBytes(salt + passWord); //將鹽值和密碼進行組合 SHA256Managed hashstring = new SHA256Managed(); byte[] hash = hashstring.ComputeHash(bytes);//針對組合後的數據應用hash函數 string hashString = string.Empty; foreach (byte x in hash) { hashString += String.Format("{0:x2}", x); } return hashString; //獲得加密後的密文字符串 }
應用效果:
Console.WriteLine("請輸入新密碼(若取消請按ESC鍵):"); string passWord = string.Empty; bool isSucessed = GetUserInput(out passWord);//獲取用戶輸入 if (isSucessed == false) break; string salt = string.Empty; string passWordHash = GetHashSha256AndSalt(passWord, out salt);//對密碼進行加密 Console.WriteLine("SHA256對應hash值爲:{0}\n鹽值爲:{1}", passWordHash, salt);
對應輸出:
請輸入新密碼(若取消請按ESC鍵): ****** SHA256對應hash值爲:a5e5623028967e78ee79aa5aa8a6613d60252b9984af5db4e0c00e7de564d12f 鹽值爲:dPBQ6pbaCBaQjwlXv0B44gj4ErTRMo+1Dn5BQPgdxeMNvZu3qV+XlBlG+nict9bN0rQITbqzpzY1zXG5JxkBPQeVagsk05nUqDamP7Lhc4XEFrQrQn86oqKsCaG988Too2ad85ns4B7TmMswTWKsGzA3xWKQj2qjtMnaMB2NwHBpMD2jxnQLdGQEtIw8nF+m4xOA8U3wAeHPAnbIai+mt4k4DgI7OMitm42I80geO7vQexfGXcHR1c7j2hO++6aqb+jbpHwTmgtvi83gNghDj/iG67jk2a0FX8N0/knalhgHhmGom7rCuWmA86llfkk4H1cAfHImnA6cUiL2Viau2w==
/// <summary> /// 密碼校驗 /// </summary> /// <param name="passWordHash">密碼的hash值</param> /// <param name="salt">鹽值</param> private static bool ValidPSW(string passWordHash, string salt) { Console.WriteLine("請再次輸入密碼進行校驗(若取消請按ESC鍵):"); string passWord = string.Empty; bool isSucessed = GetUserInput(out passWord); if (isSucessed == false) return false; string passWordHashNew = GetHashSha256(passWord, salt); //將用戶數據的密碼採用已知的鹽值進行加密 bool isValid = SlowEquals(passWordHashNew, passWordHash);//校驗密碼hash值是否一致 if (isValid) { Console.WriteLine("密碼校驗經過"); } else { Console.WriteLine("兩次輸入密碼不一致"); return ValidPSW(passWordHash, salt); } Console.WriteLine(); return true; }
應用效果:
輸出: 請再次輸入密碼進行校驗(若取消請按ESC鍵): ****** 兩次輸入密碼不一致 請再次輸入密碼進行校驗(若取消請按ESC鍵): ****** 密碼校驗經過
http://drops.wooyun.org/papers/1066
http://crackstation.net/hashing-security.htm
其餘:本文系信息安全做業,純原創,轉載請標明出處