密碼驗證是很常見的需求,如何在實現功能之餘,防止用戶密碼泄露,已經有了很成熟的方案。這篇文章把本身的思考和結論作一下記錄。php
對用戶密碼進行加密時須要作到:算法
1.交給https,明文傳輸。
2.客戶端將密碼加鹽(鹽隨機生成、具備強度)並哈希。服務端再次加鹽哈希並對比。假設https被竊聽,攻擊者破解密碼明文也具備至關難度。數據庫
1.增長哈希算法強度。
2.隨機生成具備強度的鹽。安全
哈希算法是不可逆的。攻擊者能夠生成海量的密碼 -> 哈希值鍵值對,反向映射,有機率經過哈希值獲得密碼。
故,破解的成本=哈希算法強度×鹽值數量。函數
若是鹽不隨機,攻擊者能夠針對單個鹽生成哈希值->密碼鍵值對,再對整個數據庫的哈希值作匹配。
假設鹽是保密的,鹽可能由於各類緣由被攻擊者獲取(代碼泄漏、社會工程學等等)。
攻擊者也能夠經過在數據庫被攻破的網站上註冊用戶,經過 哈希值->攻擊者密碼+鹽 來破解鹽。網站
若是鹽的強度(長度)不夠。攻擊者能夠創建多個 哈希值->密碼 數據庫,簡單鹽被匹配(攻破)的機率更高。ui
攻擊者很難有足夠的計算資源和存儲空間創建海量的 哈希值->密碼 數據庫,針對單條用戶記錄,創建 哈希值->密碼 數據庫進行攻擊的成本太高。加密
需求是房間密碼,出於簡單考慮,我最初的想法是,MD5+隨機鹽。
在數據庫裏大體是這樣:spa
+-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | uid | int(11) | NO | PRI | NULL | | | pwd | varchar(45) | YES | | NULL | | | salt | varchar(45) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+
php的md5文檔
http://php.net/manual/zh/func...
給了一個很好的指引:
http://php.net/manual/zh/faq....
password_hash 和 crypt 函數返回值的組成部分,依次爲:所選擇的算法,算法選項,所使用的「鹽」,以及散列後的密碼。
更改後、數據庫表變爲:.net
+-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | uid | int(11) | NO | PRI | NULL | | | pwd | varchar(255) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+
相較以前的方案:
1.記錄了採用的算法(能夠在不改動代碼的狀況下升級算法)
2.記錄了採用算法的cost(強度),能夠在硬件計算能力上升的狀況下,調整cost來維持安全性。
3.鹽和哈希值一併返回,簡化了接口調用、數據庫存儲。
php的驗證接口設計得至關漂亮。
使用簡單,強制調用者使用隨機的salt(不容易誤用),可在不修改代碼的狀況下拓展算法強度。
代碼:
if (!empty($xxxx_info['pwd'])) { // 若原來有密碼,則要檢測 if (!password_verify($old_pwd, $xxxx_info['pwd'])) { // 用戶名或密碼錯 return; } } // 對密碼長度、內容等不作限制。 // 以應用場景來講,123456之類也無所謂。 $pwd_in_db = password_hash($new_pwd, PASSWORD_DEFAULT, array("cost" => 6));
http://php.net/manual/zh/faq....
http://www.infoq.com/cn/artic...