PHP更安全的密码加密机制Bcrypt详解
前言
我们常常为了避免在服务器受到攻击,数据库被拖库时,用户的明文密码不被泄露,一般会对密码进行单向不可逆加密——哈希。
常见的方式是:
哈希方式 | 加密密码 |
md5(‘123456') | e10adc3949ba59abbe56e057f20f883e |
md5(‘123456'.($salt=‘salt')) | 207acd61a3c1bd506d7e9a4535359f8a |
sha1(‘123456') | 40位密文 |
hash(‘sha256',‘123456') | 64位密文 |
hash(‘sha512',‘123456') | 128位密文 |
密文越长,在相同机器上,进行撞库消耗的时间越长,相对越安全。
比较常见的哈希方式是md5+盐,避免用户设置简单密码,被轻松破解。
password_hash
但是,现在要推荐的是password_hash()函数,可以轻松对密码实现加盐加密,而且几乎不能破解。
$password='123456'; var_dump(password_hash($password,PASSWORD_DEFAULT)); var_dump(password_hash($password,PASSWORD_DEFAULT));
password_hash生成的哈希长度是PASSWORD_BCRYPT——60位,PASSWORD_DEFAULT——60位~255位。PASSWORD_DEFAULT取值跟php版本有关系,会等于其他值,但不影响使用。
每一次password_hash运行结果都不一样,因此需要使用password_verify函数进行验证。
$password='123456'; $hash=password_hash($password,PASSWORD_DEFAULT); var_dump(password_verify($password,$hash));
password_hash会把计算hash的所有参数都存储在hash结果中,可以使用password_get_info获取相关信息。
$password='123456'; $hash=password_hash($password,PASSWORD_DEFAULT); var_dump(password_get_info($hash));
输出
array(3){ ["algo"]=> int(1) ["algoName"]=> string(6)"bcrypt" ["options"]=> array(1){ ["cost"]=> int(10) } }
注意:不包含salt
可以看出我当前版本的PHP使用PASSWORD_DEFAULT实际是使用PASSWORD_BCRYPT。
password_hash($password,$algo,$options)的第三个参数$options支持设置至少22位的salt。但仍然强烈推荐使用PHP默认生成的salt,不要主动设置salt。
当要更新加密算法和加密选项时,可以通过password_needs_rehash判断是否需要重新加密,下面的代码是一段官方示例
$options=array('cost'=>11); //Verifystoredhashagainstplain-textpassword if(password_verify($password,$hash)) { //Checkifanewerhashingalgorithmisavailable //orthecosthaschanged if(password_needs_rehash($hash,PASSWORD_DEFAULT,$options)) { //Ifso,createanewhash,andreplacetheoldone $newHash=password_hash($password,PASSWORD_DEFAULT,$options); } //Loguserin }
password_needs_rehash可以理解为比较$algo+$option和password_get_info($hash)返回值。
password_hash运算慢
password_hash是出了名的运行慢,也就意味着在相同时间内,密码重试次数少,泄露风险降低。
$password='123456'; var_dump(microtime(true)); var_dump(password_hash($password,PASSWORD_DEFAULT)); var_dump(microtime(true)); echo"\n"; var_dump(microtime(true)); var_dump(md5($password)); for($i=0;$i<999;$i++) { md5($password); } var_dump(microtime(true));
输出
float(1495594920.7034) string(60)"$2y$10$9ZLvgzqmiZPEkYiIUchT6eUJqebekOAjFQO8/jW/Q6DMrmWNn0PDm" float(1495594920.7818) float(1495594920.7818) string(32)"e10adc3949ba59abbe56e057f20f883e" float(1495594920.7823)
password_hash运行一次耗时784毫秒,md5运行1000次耗时5毫秒。这是一个非常粗略的比较,跟运行机器有关,但也可以看出password_hash运行确实非常慢。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。