如何對用戶密碼進行加密

摘要

密碼驗證是很常見的需求,如何在實現功能之餘,防止用戶密碼泄露,已經有了很成熟的方案。這篇文章把本身的思考和結論作一下記錄。php

結論

對用戶密碼進行加密時須要作到:算法

防止用戶密碼明文被竊聽

1.交給https,明文傳輸。
2.客戶端將密碼加鹽(鹽隨機生成、具備強度)並哈希。服務端再次加鹽哈希並對比。假設https被竊聽,攻擊者破解密碼明文也具備至關難度。數據庫

防止數據庫被攻破時,用戶密碼明文被竊取。

1.增長哈希算法強度。
2.隨機生成具備強度的鹽。安全

一些思考

哈希算法是不可逆的。攻擊者能夠生成海量的密碼 -> 哈希值鍵值對,反向映射,有機率經過哈希值獲得密碼。
故,破解的成本=哈希算法強度×鹽值數量。函數

如何選擇哈希算法強度

  • 計算耗時用戶可接受(視應用場景,如0.2S內)。
  • 計算耗時儘可能長,即增長哈希算法強度。

爲何鹽要隨機

若是鹽不隨機,攻擊者能夠針對單個鹽生成哈希值->密碼鍵值對,再對整個數據庫的哈希值作匹配。
假設鹽是保密的,鹽可能由於各類緣由被攻擊者獲取(代碼泄漏、社會工程學等等)。
攻擊者也能夠經過在數據庫被攻破的網站上註冊用戶,經過 哈希值->攻擊者密碼+鹽 來破解鹽。網站

爲何鹽要有強度

若是鹽的強度(長度)不夠。攻擊者能夠創建多個 哈希值->密碼 數據庫,簡單鹽被匹配(攻破)的機率更高。ui

爲何鹽能夠明文存儲

攻擊者很難有足夠的計算資源和存儲空間創建海量的 哈希值->密碼 數據庫,針對單條用戶記錄,創建 哈希值->密碼 數據庫進行攻擊的成本太高。加密

php的實現

最初的想法

需求是房間密碼,出於簡單考慮,我最初的想法是,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的推薦實現

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...

相關文章
相關標籤/搜索