PHP中的密码加密的解决方案总结


Posted in PHP onOctober 26, 2016

层出不穷的类似事件对用户会造成巨大的影响,因为人们往往习惯在不同网站使用相同的密码,一家“暴库”,全部遭殃

一般的解决方案。

1、将明文密码做单向hash

$password = md5($_POST["password"]);

2、密码+salt后做单向hash,PHP内置了hash()函数,你只需要将加密方式传给hash()函数就好了。你可以直接指明sha256, sha512, md5, sha1等加密方式

<?php
 
function generateHashWithSalt($password) {
 $intermediateSalt = md5(uniqid(rand(), true));
 $salt = substr($intermediateSalt, 0, 6);
 return hash("sha256", $password . $salt);
}
?>

单向哈希算法有一个特性,无法通过哈希后的摘要(digest)恢复原始数据,常用的单向哈希算法包括SHA-256,SHA-1,MD5等。例如,对密码“passwordhunter”进 行SHA-256哈希后的摘要(digest)如下:
“bbed833d2c7805c4bf039b140bec7e7452125a04efa9e0b296395a9b95c2d44c”

注意:攻击者可以将所有密码的常见组合进行单向哈希,得到一个摘要组合,然后与数据库中的摘要进行比对即可获得对应的密码。这个摘要组合也被称为rainbow table。更糟糕的是,一个攻击者只要建立上述的rainbow table,可以匹配所有的密码数据库。仍然等同于一家“暴库”,全部遭殃

比较好的解决方案

Bcrypt

<?php
function generateHash($password) {
 if (defined("CRYPT_BLOWFISH") && CRYPT_BLOWFISH) {
  $salt = '$2y$11$' . substr(md5(uniqid(rand(), true)), 0, 22);
  return crypt($password, $salt);
 }
}
?>

Bcrypt 其实就是Blowfish和crypt()函数的结合,我们这里通过CRYPT_BLOWFISH判断Blowfish是否可用,然后像上面一样生成一个盐值,不过这里需要注意的是,crypt()的盐值必须以2a2a或者2y2y开头,详细资料可以参考下面的链接:

http://www.php.net/security/crypt_blowfish.php

http://php.net/manual/en/function.crypt.php

Password Hashing API

Password Hashing API是PHP 5.5之后才有的新特性,它主要是提供下面几个函数供我们使用

password_hash() ? 对密码加密.
password_verify() ? 验证已经加密的密码,检验其hash字串是否一致.
password_needs_rehash() ? 给密码重新加密.
password_get_info() ? 返回加密算法的名称和一些相关信息.

虽然说crypt()函数在使用上已足够,但是password_hash()不仅可以使我们的代码更加简短,而且还在安全方面给了我们更好的保障,所以,现在PHP的官方都是推荐这种方式来加密用户的密码,很多流行的框架比如Laravel就是用的这种加密方式

<?php
$hash = password_hash($passwod, PASSWORD_DEFAULT);?>

PASSWORD_DEFAULT目前使用的就是Bcrypt,最好的还是Password Hashing API。这里需要注意的是,如果你代码使用的都是PASSWORD_DEFAULT加密方式,那么在数据库的表中,password字段就得设置超过60个字符长度,你也可以使用PASSWORD_BCRYPT,这个时候,加密后字串总是60个字符长度。

这里使用password_hash()你完全可以不提供盐值(salt)和 消耗值 (cost),你可以将后者理解为一种性能的消耗值,cost越大,加密算法越复杂,消耗的内存也就越大。当然,如果你需要指定对应的盐值和消耗值,你可以这样写

<?php
function custom_function_for_salt(){
 return $salt = '$2y$11$' . substr(md5(uniqid(rand(), true)), 0, 22);
}
 
$password =123456;
 
$options = [
 'salt' => custom_function_for_salt(), //write your own code to generate a suitable salt
 'cost' => 12 // the default cost is 10
];
$hash = password_hash($password, PASSWORD_DEFAULT, $options);
echo $hash;
?>

密码加密过后,我们需要对密码进行验证,以此来判断用户输入的密码是否正确

<?php
if (password_verify($password, $hash)) {
 // Pass
}
else {
 // Invalid
}

直接使用password_verify就可以对我们之前加密过的字符串(存在数据库中)进行验证了

如果有时候我们需要更改我们的加密方式,如某一天我们突然想更换一下盐值或者提高一下消耗值,我们这时候就要使用到password_needs_rehash()函数了

<?php
if (password_needs_rehash($hash, PASSWORD_DEFAULT, ['cost' => 12])) {
 // cost change to 12
 $hash = password_hash($password, PASSWORD_DEFAULT, ['cost' => 12]);
 
 // don't forget to store the new hash!
}

只有这样,PHP的Password Hashing API才会知道我们重现更换了加密方式,这样的主要目的就是为了后面的密码验证,password_get_info(),这个函数一般可以看到下面三个信息

algo ? 算法实例
algoName ? 算法名字
options ? 加密时候的可选参数

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
Php output buffering缓存及程序缓存深入解析
Jul 15 PHP
PHP_NETWORK_GETADDRESSES: GETADDRINFO FAILED问题解决办法
May 04 PHP
PHP简单获取及判断提交来源的方法
Apr 22 PHP
php用户登录之cookie信息安全分析
May 13 PHP
PHP实现数据分页显示的简单实例
May 26 PHP
thinkPHP模板算术运算相关函数用法分析
Jul 12 PHP
详解EventDispatcher事件分发组件
Dec 25 PHP
php 中奖概率算法实现代码
Jan 25 PHP
php实现数据库的增删改查
Feb 26 PHP
php字符串过滤strip_tags()函数用法实例分析
Jun 24 PHP
Laravel5.5 实现后台管理登录的方法(自定义用户表登录)
Sep 30 PHP
YII2框架中behavior行为的理解与使用方法示例
Mar 13 PHP
php 解析xml 的四种方法详细介绍
Oct 26 #PHP
PHP 以POST方式提交XML、获取XML,解析XML详解及实例
Oct 26 #PHP
php 生成签名及验证签名详解
Oct 26 #PHP
PHP XML和数组互相转换详解
Oct 26 #PHP
PHP对XML内容进行修改和删除实例代码
Oct 26 #PHP
php array_merge_recursive 数组合并
Oct 26 #PHP
php抛出异常与捕捉特定类型的异常详解
Oct 26 #PHP
You might like
用PHP的ob_start();控制您的浏览器cache!
2007/02/14 PHP
php几个预定义变量$_SERVER用法小结
2014/11/07 PHP
PHP实现更改hosts文件的方法示例
2017/08/08 PHP
网页javascript精华代码集
2007/01/24 Javascript
input的focus方法使用
2010/03/13 Javascript
浅析JavaScript中的typeof运算符
2013/11/30 Javascript
JavaScript静态类型检查工具FLOW简介
2015/01/06 Javascript
JS实现网页上随滚动条滚动的层效果代码
2015/11/04 Javascript
js检测离开或刷新页面时表单数据是否更改的方法
2016/08/02 Javascript
微信小程序 Canvas增强组件实例详解及源码分享
2017/01/04 Javascript
基于JavaScript实现带缩略图的轮播效果
2017/01/12 Javascript
JS实现含有中文字符串的友好截取功能分析
2017/03/13 Javascript
Angularjs自定义指令Directive详解
2017/05/27 Javascript
详解node如何让一个端口同时支持https与http
2017/07/04 Javascript
详解React-Native解决键盘遮挡问题(Keyboard遮挡问题)
2017/07/13 Javascript
关于JavaScript中forEach和each用法浅析
2017/07/27 Javascript
JS操作时间 - UNIX时间戳的简单介绍(必看篇)
2017/08/16 Javascript
Vue cli+mui 区域滚动的实例代码
2018/01/25 Javascript
微信小程序与公众号卡券/会员打通的问题
2019/07/25 Javascript
[44:40]KG vs LGD 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
Python多线程学习资料
2012/12/19 Python
python实现批量转换文件编码(批转换编码示例)
2014/01/23 Python
处理Python中的URLError异常的方法
2015/04/30 Python
Python微医挂号网医生数据抓取
2019/01/24 Python
利用Python绘制Jazz网络图的例子
2019/11/21 Python
Python selenium的基本使用方法分析
2019/12/21 Python
python GUI库图形界面开发之PyQt5 MDI(多文档窗口)QMidArea详细使用方法与实例
2020/03/05 Python
HTML5+CSS3实例 :canvas 模拟实现电子彩票刮刮乐代码
2016/12/30 HTML / CSS
银行职员个人的工作自我评价
2014/02/15 职场文书
手术室护士节演讲稿
2014/08/27 职场文书
开展党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
2014年行政人事工作总结
2014/12/09 职场文书
租赁协议书
2015/01/27 职场文书
银行柜员工作心得体会
2016/01/23 职场文书
2016优秀青年志愿者事迹材料
2016/02/25 职场文书
深入浅析python3 依赖倒置原则(示例代码)
2021/07/09 Python