密码验证是很常见的需求,如何在实现功能之余,防止用户密码泄露,已经有了很成熟的方案。这篇文章把本身的思考和结论作一下记录。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...