如何在PHP中使用bcrypt对密码进行哈希处理?

我不时听到这样的建议:“使用bcrypt在PHP中存储密码,使用bcrypt规则”

但是什么是bcrypt?PHP不提供任何此类功能,Wikipedia喋喋不休地谈论一个文件加密实用程序,Web搜索只是展示了几种不同语言的Blowfish实现。现在,Blowfish也可以通过mcrypt在PHP中使用,但是这对存储密码有什么帮助呢?河豚是一种通用密码,它有两种工作方式。如果可以加密,就可以解密。密码需要一个单向散列函数

原因是什么

bcrypt是一种哈希算法,可通过硬件(通过可配置的轮数)进行扩展。它的缓慢和多轮确保攻击者必须部署大量资金和硬件才能破解您的密码。再加上每个密码的盐分(bcrypt需要盐分),您可以确定,如果没有数额惊人的资金或硬件,攻击几乎是不可行的

bcrypt使用Eksblowfish算法散列密码。虽然EksblowfishBlowfish的加密阶段完全相同,但是Eksblowfish的密钥调度阶段确保任何后续状态都依赖于salt和密钥(用户密码),并且在不了解两者的情况下,无法预计算任何状态由于此密钥差异,bcrypt是一种单向散列算法。在不知道salt的情况下,无法检索纯文本密码,将和密钥(密码)舍入。[来源]

如何使用bcrypt:

使用PHP>=5.5-DEV

密码散列函数现在已经直接内置到PHP>=5.5中。您现在可以使用password\u hash()创建任何密码的bcrypt哈希:

<?php
//用法1:
回显密码\u散列('rasmuslerdorf',密码\u默认值)。“\n”;
//$2y$10$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//例如:
//$2y$10$.VGA1O9WMRJRWAD98HNOGSNPCZLQM3JQ7KNED1RVAGV3FYKK1A
//用法2:
$options=[
“成本”=>11
];
回显密码\u散列('rasmuslerdorf',密码\u BCRYPT,$options)。“\n”;
//$2y$11$6DP.V0nO7YI3iSki4qog6OQI5eiO6Jnjsqg7vdnb.JgGIsxniOn4C

要根据现有哈希值验证用户提供的密码,可以使用密码\u verify()

<?php
//请参阅password_hash()示例以了解其来源。
$hash='$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';
if(密码验证('rasmuslerdorf',$hash)){
echo“密码有效!”;
}否则{
回显“无效密码”;
}

使用PHP>=5.3.7,<5.5-DEV(也是RedHat PHP>=5.3.3)

GitHub上有一个兼容性库,它是基于最初用C编写的上述函数的源代码创建的,提供了相同的功能。安装兼容性库后,用法与上面相同(如果您仍在5.3.x分支上,则减去速记数组符号)

使用PHP<5.3.7(已弃用)

您可以使用crypt()函数来生成输入字符串的bcrypt哈希。此类可以自动生成SALT并根据输入验证现有哈希如果您使用的PHP版本高于或等于5.3.7,强烈建议您使用内置函数或compat库。此备选方案仅用于历史目的

类Bcrypt{
私人$rounds;
公共功能构造($rounds=12){
如果(穴魟河豚!=1){
抛出新异常(“bcrypt”在此安装中不受支持。请参阅http://php.net/crypt");
}
$this->rounds=$rounds;
}
公共函数散列($input){
$hash=crypt($input,$this->getSalt());
if(strlen($hash)>13)
返回$hash;
返回false;
}
公共函数验证($input,$existingHash){
$hash=crypt($input,$existingHash);
返回$hash===$existingHash;
}
私有函数getSalt(){
$salt=sprintf($2a$%02d$,$this->轮);
$bytes=$this->getRandomBytes(16);
$salt.=$this->encodeBytes($bytes);
退还$salt;
}
私人和国家;
私有函数getRandomBytes($count){
$bytes='';
if(函数_存在('openssl_随机_伪_字节')&
(strtoupper(substr(PHP_-OS,0,3))!=='WIN'){//OpenSSL在Windows上运行缓慢
$bytes=openssl\u random\u pseudo\u字节($count);
}
如果($bytes==''可读('/dev/uradom')&
([email protected]('/dev/uradom','rb'))!==FALSE){
$bytes=fread($hRand,$count);
fclose($hRand);
}
if(strlen($bytes)<$count){
$bytes='';
如果($this->randomState==null){
$this->randomState=microtime();
如果(函数_存在('getmypid')){
$this->randomState.=getmypid();
}
}
对于($i=0;$i<$count;$i+=16){
$this->randomState=md5(microtime().$this->randomState);
如果(PHP_版本>=“5”){
$bytes.=md5($this->randomState,true);
}否则{
$bytes.=pack('H*',md5($this->randomState));
}
}
$bytes=substr($bytes,0,$count);
}
返回$bytes;
}
私有函数encodeBytes($input){
//下面是PHP密码哈希框架中的代码
$itoa64='。/ABCDEFGHIjklmnopqrstuvwxyzabCDEFGHIjklmnopqrstuvwxyzo123456789';
$output='';
$i=0;
做{
$c1=ord($input[$i++]);
$output.=$itoa64[$c1>2];
$c1=($c1&0x03)<4;
如果($i>=16){
$output.=$itoa64[$c1];
打破
}
$c2=ord($input[$i++]);
$c1 |=$c2>>4;
$output.=$itoa64[$c1];
$c1=($c2&0x0f)<2;
$c2=ord($input[$i++]);
$c1 |=$c2>>6;
$output.=$itoa64[$c1];
$output.=$itoa64[$c2&0x3f];
}虽然(正确);
返回$output;
}
}

您可以这样使用此代码:

$bcrypt=新的bcrypt(15);
$hash=$bcrypt->散列(‘密码’);
$isGood=$bcrypt->验证('password',$hash);

或者,您也可以使用可移植的PHP哈希框架

发表评论