用戶密碼安全性設計

1:淺談密碼加SALT原理javascript

咱們知道,若是直接對密碼進行散列,那麼黑客能夠對經過得到這個密碼散列值,而後經過查散列值字典(例如MD5密碼破解網站),獲得某用戶的密碼。
 
  加Salt能夠必定程度上解決這一問題。所謂加Salt方法,就是加點「佐料」。其基本想法是這樣的:當用戶首次提供密碼時(一般是註冊時),由系統自動往這個密碼裏撒一些「佐料」,而後再散列。而當用戶登陸時,系統爲用戶提供的代碼撒上一樣的「佐料」,而後散列,再比較散列值,已肯定密碼是否正確。
 
  這裏的「佐料」被稱做「Salt值」,這個值是由系統隨機生成的,而且只有系統知道。這樣,即使兩個用戶使用了同一個密碼,因爲系統爲它們生成的salt值不一樣,他們的散列值也是不一樣的。即使黑客能夠經過本身的密碼和本身生成的散列值來找具備特定密碼的用戶,但這個概率過小了(密碼和salt值都得和黑客使用的同樣才行)。
 
下面以PHP示例,講解md5($pass.$salt)加密函數。
 
<?php
function hash($a) {
    $salt=」Random_KUGBJVY」;  //定義一個salt值,程序員規定下來的隨機字符串
    $b=$a.$salt;  //把密碼和salt鏈接
    $b=md5($b);  //執行MD5散列
    return $b;  //返回散列   
}
?>
 
  調用方式:$new_password=hash($_POST[password]);   //這裏接受表單提交值,並進行加密
 
  下面詳細介紹一下加Salt散列的過程。介紹以前先強調一點,前面說過,驗證密碼時要使用和最初散列密碼時使用「相同的」佐料。因此Salt值是要存放在數據庫裏的。
 
用戶註冊時,
 
用戶輸入【帳號】和【密碼】(以及其餘用戶信息);系統爲用戶生成【Salt值】;系統將【Salt值】和【用戶密碼】鏈接到一塊兒;對鏈接後的值進行散列,獲得【Hash值】;將【Hash值1】和【Salt值】分別放到數據庫中。
用戶登陸時,
 
用戶輸入【帳號】和【密碼】;系統經過用戶名找到與之對應的【Hash值】和【Salt值】;系統將【Salt值】和【用戶輸入的密碼】鏈接到一塊兒;對鏈接後的值進行散列,獲得【Hash值2】(注意是即時運算出來的值);比較【Hash值1】和【Hash值2】是否相等,相等則表示密碼正確,不然表示密碼錯誤。
有時候,爲了減輕開發壓力,程序員會統一使用一個salt值(儲存在某個地方),而不是每一個用戶都生成私有的salt值php

 

轉自:http://www.2cto.com/Article/201201/117051.htmlhtml

 

============更詳細的介紹=================java

 

設計安全的帳號系統的正確姿式

字數4826 閱讀2712 評論17 喜歡98程序員

引子

最近有個虛擬練習項目,涉及到系統安全保障的設計,因而對安全保障這塊作了一些更深刻的瞭解。發現了不少有趣的東西,開闊了眼界。中間查了一些資料,因而我打算從新整理,用更加按部就班,你們都能懂的方式,說一說如何設計一個安全的系統。算法

著名的安全事件

首先來看看最近幾年比較著名的拖庫撞庫後密碼泄露的事件:數據庫

  1. 2011年12月,國內最大的程序員社區 CSDN 遭拖庫,600萬個帳戶信息泄露。
  2. 2014年3月,攜程旅行網的系統存技術漏洞,漏洞可能致使用戶的姓名、身份證號碼、銀行卡類別、銀行卡卡號、銀行卡CVV碼以及銀行卡6位Bin泄露。
  3. 2014年5月,小米論壇涉及800萬用戶信息遭泄露,信息包括用戶名、密碼、註冊IP、郵箱等。
  4. 2014年12月,12306遭撞庫攻擊,13萬用戶信息泄露,包括用戶帳號、明文密碼、身份證、郵箱等敏感信息。
  5. 2015年10月,網易郵箱遭攻擊,近5億條用戶信息被泄露,包括用戶名、密碼、密碼保護信息、登錄IP以及用戶生日等多個原始信息。

除了密碼泄露事件,數據被物理刪除的事件也是發生:瀏覽器

2015年5月,攜程網及APP陷入癱瘓,數據庫遭物理刪除疑似離職員工報復。安全

這麼多大公司大網站的系統都遭到攻擊,泄露用戶信息,更別說其餘小網站了。這些攻擊均可以從技術上來進行防範的,可是咱們看到即便是大公司,安全方面也是那麼的薄弱。服務器

防範方法

防範的方法簡單來講數據從用戶鍵盤敲出的那一刻,到服務器後臺存儲都要保持正確的姿式。好比:

  1. 用正確的姿式保存密碼。
  2. 用正確的姿式傳輸數據。
  3. 用正確的姿式加密敏感信息。
  4. 用正確的姿式對數據進行備份和監控。

用正確的姿式保存密碼

這一步很是重要,也比較複雜。用戶在瀏覽器裏輸入密碼,傳輸到服務器端進行驗證,服務端將以前保存的密碼信息和用戶的輸入進行比對。

1. 低級錯誤:明文保存密碼

安全性最低的是在服務端明文保存用戶的密碼,一旦服務器被入侵,數據被拖走(拖庫),全部用戶的密碼都直接的暴露在外面。這是最初級的作法,毫無安全性可言。假如你在一個網站或論壇註冊了一個帳號,該網站自動發了一封郵件告訴你註冊成功,裏面明文寫了你的密碼,趕忙把密碼改了而後不再要訪問這個網站。

2. 低級錯誤:可逆加密密碼

既然不能明文保存密碼,那固然是加密保存了。耍個小聰明,好比把密碼的字母倒着存,或者每一個字母存後一個字母,或者進行異或混淆處理,表面上密碼看上去已經看不出來原始的密碼是什麼了,但實際上這個和明文保存密碼並無本質區別,由於黑客既然能夠入侵你的服務器,天然能夠拿到你的加密代碼,只要按你的算法進行簡單的解密就能夠獲得原始密碼。

3. 錯誤方法:md5 加密密碼

在我仍是一個初學者的時候,我已被告知不能用前兩種方式保存密碼,當時的主流方法是使用 md5 加密密碼。(年代久遠,如今已絕非主流了。) md5 是一種不可逆的加密方法,即密碼被 md5 加密後是沒法解密出原始密碼的,驗證密碼是否正確的方法是將用戶輸入的密碼 md5 加密後於數據庫裏保存的 md5 機密後的結果進行比對。這樣,服務器端在不知道真實用戶密碼的狀況下也能對用戶密碼進行驗證了。

這是早期比較主流的作法,然而,這依然是很是不安全的。由於只要枚舉全部短密碼進行 md5 加密,作成一個索引表,就能輕易的逆推出原始密碼。這種預先計算好的用於逆推加密散列函數的表就是「彩虹表」。隨着「彩虹表」不斷變大,md5 的加密已經變得很是的不安全。2015年10月網易郵箱的用戶密碼泄露也被懷疑只對密碼進行了 md5 加密。

4. 正確方法:加鹽 hash 保存密碼

加鹽 hash 是指在加密密碼時,不僅是對密碼進行 hash ,而是對密碼進行調油加醋,放點鹽(salt)再加密,一方面,因爲你放的這點鹽,讓密碼自己更長強度更高,彩虹表逆推的難度更大,也因你放的這點鹽,讓黑客進行撞庫時運算量更大,破解的難度更高。

如何進行加鹽就是一門很重要的學問了。md5 是一種 hash 算法,如下就拿 md5 來舉例。假如密碼是 123456 ,md5 的結果以下:

像 123456 這樣的簡單密碼,是很容易被逆推出來的。可是假如咱們往簡單密碼里加點鹽試試:

上面例子裏的 #g5Fv;0Dvk 就是咱們加的鹽。加完以後,密碼的強度更高了,彩虹表破解的難度加大了。或者進行加鹽兩次 md5 :

到這裏,你必定會有疑問,是否是把 md5 多作幾回,或者自定義一些組合的方式就更安全了。其實不是的,黑客既然能拿到數據庫裏的數據,也頗有可能拿到你的代碼。

一個健壯的、牢不可破的系統應該是:

即便被拿走了數據和全部的代碼,也沒辦法破解裏面的數據。

這也是爲何你們沒必要實現本身的加密算法,而是使用公開的加密算法的緣由,好比:RSA、AES、DES 等等。既然沒法保證加密代碼不被泄露,那就使用公開的加密算法,只要保護好私鑰信息,就算你知道個人加密方式也沒有任何幫助。

大部分狀況下,使用 md5(md5(password) + salt) 方式加密基本上已經能夠了:

其中,最關鍵的是 salt 從哪裏來? salt 該怎麼設置才能安全。有幾個重要的點:

  1. 不要使用固定不變的 salt。
  2. 每一個用戶的 salt 都須要不一樣。
  3. salt 必須由服務端使用安全的隨機函數生成。
  4. 客戶端運算須要的 salt 須要從服務端動態獲取。
  5. 客戶端加鹽 hash 的結果並非最終服務端存盤的結果。

因爲客戶端也須要執行加鹽 hash ,因此,salt 不能直接寫在客戶端,而是應該動態從服務端得到。服務端生成隨機的 salt 時,必須使用安全的隨機函數,防止隨機數被預測。

各語言安全的隨機函數:

Platform CSPRNG
PHP mcrypt_create_iv, openssl_random_pseudo_bytes
Java java.security.SecureRandom
Dot NET (C#, VB) System.Security.Cryptography.RNGCryptoServiceProvider
Ruby SecureRandom
Python os.urandom
Perl Math::Random::Secure
C/C++ (Windows API) CryptGenRandom
Any language on GNU/Linux or Unix Read from /dev/random or /dev/urandom

就算 salt 值動態從服務端獲取,也有可能被中間人攔截獲取。同時,客戶端的加鹽 hash 的過程至關因而徹底暴露的。一種更安全的作法是,客戶端使用 javascript 進行加鹽 hash,把結果傳到服務器後,服務器對結果再進行一次 加鹽 hash 或者 加密 hash(好比:HMAC) ,而後再和數據庫的結果進行比對。

若是須要達到更高的安全等級,能夠考慮:

1. 使用更安全的 hash 函數用來抵抗碰撞攻擊,好比:SHA256, SHA512, RipeMD, WHIRLPOOL。

兩個不一樣的內容 hash 的結果可能相同,攻擊者在不知道真實密碼的狀況下,使用其餘密碼進行碰撞攻擊從而登陸系統。使用更安全的 hash 函數能夠減小這種狀況的發生。

2. 可使用一種大量消耗 cpu 的 hash 算法對抗暴力破解,好比PBKDF2 或者 bcrypt。

暴力破解就是枚舉全部可能的密碼進行嘗試驗證,使用大量消耗 cpu 的 hash 算法能夠極大增長暴力破解的時間。

3. 比較加鹽 md5 結果時,使用時間恆定的比較函數。

在比較兩個字符串時,一般都一個字符一個字符進行比較,若是某個字符不匹配就會當即返回。攻擊者能夠根據驗證的時間長短來判斷前幾位字符是否正確,而後逐步修正最終獲得正確的結果。

所以,在比較 hash 時,使用時間恆定的比較函數,可讓攻擊者摸不着頭腦。好比下面這段代碼:

private static boolean slowEquals(byte[] a, byte[] b)
{
    int diff = a.length ^ b.length;
    for(int i = 0; i < a.length && i < b.length; i++)
        diff |= a[i] ^ b[i];
    return diff == 0;
}

異或(^)操做能夠用來判斷兩個字符是否相等,好比:

0 XOR 0 = 0    1 XOR 1 = 0
0 XOR 1 = 1    1 XOR 0 = 1

上面的函數枚舉每一個字符進行異或判斷,而後將全部的結果取或運算,獲得最終的結果,比較的時間是恆定的。

4. salt 的值不要和最終 hash 的結果存在同一個數據庫。

SQL 注入是常見的攻擊手段,被注入後數據庫裏的數據被暴露無遺。因此,應該將 salt 分開存儲,存到別的機器的數據庫裏,讓攻擊者拿不到 salt ,從而沒法輕易破解信息。

5. 最終存儲的結果使用基於 key 的 hash 函數,好比 HMAC。 key 從外部安全性極高的專屬服務中得到。

有了這層加固,即便數據被拖庫,攻擊者也沒法從 hash 的結果逆推回原始密碼。由於使用了加密的 hash 函數。基於 key 的 hash 函數只是進行哈希運算時,除了傳入原始內容外,還須要傳入一個密鑰(key)。攻擊者沒有 key 幾乎不可能對數據進行解密。

key 能夠保存在極高安全性的通用的 key 管理系統,使用加密協議傳輸,對訪問者進行驗證,只容許特定的機器有權限訪問。

用正確的姿式傳輸數據

使用 HTTP 協議傳輸數據時,數據都是明文傳輸的,數據從發出到服務器接收,中間可能被劫持,篡改。好比常見的 DNS 劫持,HTTP 劫持,中間人攻擊。

用正確的姿式傳輸數據,目的就是爲了保證傳輸的數據安全,簡單概括爲兩點:

  1. 須要確保進行通信的服務端是官方的、正確的服務端,而不是跟一個假的服務端在通訊。
  2. 確保信息在網絡上傳輸時是加密的,只有客戶端和服務端有能力對數據進行解密。
  3. 確保信息在傳輸時不被篡改,或者數據被篡改時能當即發現。

1. 驗證服務端的合法性

《改變將來的九大算法》一書中提到了公鑰加密和數字簽名技術,這是進行安全通訊的基礎技術保障。這裏涉及到了加密技術,先了解兩個最基礎的概念:

  1. 對稱加密:加密和解密時使用的是同一個密鑰。
  2. 非對稱加密:須要兩個密鑰來進行加密和解密:公開密鑰(public key,簡稱公鑰)和私有密鑰(private key,簡稱私鑰) ,公鑰加密的信息只有私鑰才能解開,私鑰加密的信息只有公鑰才能解開。

非對稱加密是實現驗證服務端合法性的基礎,常見的加密算法有 RSA 、 ECC 等 。服務端生成一對公鑰和私鑰,公鑰是公開的全部人都知道,客戶端須要和服務端通訊時,使用該公鑰進行數據加密,因爲只有真實合法的服務端才擁有對應的私鑰,全部只有真實的服務端才能解密該信息,而後返回數據給客戶端時,使用客戶端本身生成的公鑰進行加密,這樣數據只有對應的客戶端才能理解。

使用 HTTPS 時,數字證書裏包含了名稱和公鑰信息,只要認證該證書是合法的,而且對方能理解用該公鑰加密的信息,就能肯定是合法的服務端。

2. 確保通訊的安全

既然使用非對稱加密的方式,能夠保證雙方安全的通訊,那是否是就一直使用非對稱加密傳輸數據就好了?理論上是能夠的,可是非對稱加密的效率要比對稱加密的效率低不少。一般的作法是,經過非對稱加密的方法,協商出一個只有雙方知道的對稱加密密鑰。

即便在不安全的通訊環境下,也能夠協商出一個只有雙方纔知道的對稱加密密鑰。在《改變將來的九大算法》一書裏,有一個經典的描述如何交互密鑰的例子(在全部溝通都是透明的狀況下,如何協商出一個只有你和阿諾德才知道的顏料顏色。):

ECDH 就是基於上面原理設計的密鑰交換算法:

密鑰協商好後,雙方就可使用該密鑰進行加密傳輸了,好比使用 AES 、 DES。

因爲 ECDH 密鑰交換協議不驗證公鑰發送者的身份,所以沒法阻止中間人攻擊。若是監聽者 Mallory 截獲了 Alice 的公鑰,就能夠替換爲他本身的公鑰,並將其發送給 Bob。Mallory 還能夠截獲 Bob 的公鑰,替換爲他本身的公鑰,並將其發送給 Alice。這樣,Mallory 就能夠輕鬆地對 Alice 與 Bob 之間發送的任何消息進行解密。他能夠更改消息,用他本身的密鑰對消息從新加密,而後將消息發送給接收者。

解決方法是,Alice 和 Bob 能夠在交換公鑰以前使用數字簽名對公鑰進行簽名。

即便攻擊者不能解密傳輸的內容,但仍可使用重放攻擊嘗試身份驗證或用於欺騙系統。重放攻擊是指攻擊者將數據包截取後,向目標主機從新發送一遍數據包。

防護重放攻擊的方法主要有:

  1. 使用時間戳。數據包在必定時間範圍內纔是有效的。
  2. 使用遞增的序號。收到重複的數據包時能夠輕易的發現。
  3. 使用提問應答方式。收到數據包時能夠判斷出來是否應答過。

HTTPS 正是使用了上述的原理,保證了通訊的安全。因此,任何對安全有需求的系統都應該使用 HTTPS。若是是使用自有協議開發,好比 APP 或遊戲,應該使用上述的方法保障通訊的安全。

用正確的姿式加密敏感信息

咱們都知道,用戶的密碼不能明文保存,並且要使用不可逆的加密算法,只保存最終的 hash 結果用來驗證是否正確。那用戶其餘的敏感信息呢?好比身份證、銀行卡、信用卡等信息,該如何加密保存而不被泄露呢?

對於身份證信息,能夠像密碼同樣只保存 hash 的結果,能夠用於用戶輸入身份證號後進行驗證。假如須要給用戶顯示身份證信息,只須要保存抹掉了幾位數字的身份證號。

假如你的系統涉及到支付,須要用戶的銀行卡,信用卡(卡號,CVV碼)等信息時,必須遵循 PCI DSS (第三方支付行業數據安全標準)標準。PCI DSS 是由 PCI 安全標準委員會的創始成員(visa、mastercard、American Express、Discover Financial Services、JCB等)制定,力在使國際上採用一致的數據安全措施,包括安全管理、策略、過程、網絡體系結構、軟件設計的要求的列表等,全面保障交易安全。

若是隻是銀行卡,還須要遵循 ADSS (銀聯卡收單機構帳戶信息安全管理標準) 標準。

2014年3月攜程泄露用戶銀行卡信息就是由於沒有遵循 PCI DSS 標準。

用正確的姿式對數據進行備份和監控

2015年5月的攜程數據被刪事件,就是數據備份沒有作好的例子。數據備份是爲了防止因爲硬盤損壞或人爲破壞致使的數據丟失。主要措施有:磁盤 raid,物理備份(磁帶庫),異地的邏輯備份。同時作好權限控制,並對訪問記錄作好監控,及時發現問題,保留現場證據。

總結

本文總結了設計一個安全系統的基本原理和方法,並無舉出一個特定具體的方案,由於不一樣的系統對安全性的要求各有不一樣,設計者應該根據自身系統的特色進行具體設計。好比加鹽 hash 的具體實施方法,salt 值如何構成等等。

本文所述內容若有不實之處或者有爭議的部分,歡迎交流指出。

附錄

經常使用的加密算法:

  1. 對稱加密:DES3DES、TDEA、Blowfish、RC二、RC四、RC5IDEA、SKIPJACK、AES
  2. 非對稱加密:RSAECC(橢圓曲線加密算法)、Diffie-HellmanEl Gamal、DSA(數字簽名用)
  3. Hash 算法:MD二、MD四、MD五、HAVAL、SHA-一、SHA25六、SHA5十二、RipeMD、WHIRLPOOL、SHA三、HMAC

DES、3DES、AES 區別:

  1. DES:1976年由美國聯邦政府的國家標準局頒佈,密鑰爲 56 位。
  2. 3DES:DES加密算法的一種模式,它使用3條56位的密鑰對數據進行三次加密。
  3. AES:高級加密標準,是下一代的加密算法標準,速度快,安全級別高,用來替代原先的DES。密鑰長度能夠是128,192或256比特。

 

轉自:http://www.jianshu.com/p/e7d47efc92eb

相關文章
相關標籤/搜索