在CodeIgniter的文档中看到了对密码加密的一些建议:
从CodeIgniter的建议中我们看到像base64_encode()、base64_decode()
这种用于编码、解码的函数是不推荐用来加密的,md5()、sha1()
等弱哈希算法的函数都不是过时不推荐使用的。
文档中推荐的是5.5版本后PHP核心提供的password hashing函数族:password_get_info()
, password_hash()
, password_need_rehash()
, password_verify()
。
string password_hash ( string $password , integer $algo [, array $options ] )
password_hash()
函数使用单向强哈希算法生成一个密码哈希。password_hash()
与crypt()
兼容,password_hash()
可以使用crypt()
生成的哈希。
password_hash()
支持的哈希算法:
bcrpy
算法。需要注意的是使用这个算法的hash是会随着时间变化而变化的强算法,也是因为这个原因结果的长度也是会随时间变化而变化的。因此建议存储密码的数据库字段要超过60个字符,最佳选择是255个字符。CRYPT_BLOWFISH
算法生成一个使用$2y$
标识符的与crypt()
兼容的标准哈希。哈希的长度永远是60个字符。 参数列表
PASSWORD_BCRIPT
算法时,会把password追加到最大长度70个字符。返回值
哈希算法,salt,cost都会作为哈希的一部分返回。 所以结果中包含了password_verify
需要的所有信息。
栗子
<?php
$str = 'abc';
echo '<br />1st: '.password_hash($str, PASSWORD_BCRYPT);
echo '<br />2nd: '.password_hash($str, PASSWORD_BCRYPT);
echo '<br />3rd: '.password_hash($str, PASSWORD_BCRYPT);
这个函数至少需要两个参数。
会打印出类似下面的结果:
1st: $2y$10$.yhUghSQU9o.iBfWrtvjUOWxPlhF7SzxDr3sZFM0Pmsm6kcryWDyi
2nd:$2y$10$NZZ2lusHU67DdwmS2llSLuJ1/ynGo5NTdQsfnXoEqUp.a5Ti1FrQW
3rd:$2y$10$LB1ZzrIRAzEZiv9iHl9Yp.9WaG08h0.5/eB64w85Anrtm8fp8alsW
从上面的结果我们可以看出:
1. 每次结果都不同。
2. 三个哈希都以$2y$10$
开头,其中$2y$
是标识符,10$
是默认的cost。
我们尝试传递cost
<?php
$str = 'abc';
$options = array(
'cost'=>12
);
echo password_hash($str, PASSWORD_BCRYPT, $options);
结果为:
$2y$12$F28Fhq1ITz8yyovEW1EEdelA.nsB3WvVR.12Fks.4DoKGGnp96uCC
我们可以看到cost变成了我们自定义的值。
在介绍验证函数之前,我们先看password_get_info()
,这个函数会返回password_hash()
生成的hash的信息的数组。
array password_get_info ( string $hash )
参数列表
一个password_hash()
返回的hash。
返回值
包含三个元素的关联数组:
password_hash()
中的可选项参数。栗子
<?php
if ($hash = password_hash('abc', PASSWORD_BCRYPT, array('cost'=>12,'solt'=>'c'))){
var_dump(password_get_info($hash));
}
//结果
array(3) { ["algo"]=> int(1) ["algoName"]=> string(6) "bcrypt" ["options"]=> array(1) { ["cost"]=> int(12) } }
验证一个字符和hash是否匹配。
boolean password_verify ( string $password , string $hash )
因为password_hash()
返回了包含算法、cost、salt等信息的结果,所有password_verify()
需要的信息都包含在这个结果中,所以这个函数不需要额外的参数来传递算法、cost等信息。
参数列表
password_hash()
的返回值。返回值
匹配成功,TRUE。否则,FALSE。
栗子
<?php
$opt = array(
'cost'=>12,
'salt'=>mcrypt_create_iv(22, MCRYPT_DEV_URANDOM)
);
$password1 = 'abc';
$password2 = 'abc1';
if ($hash = password_hash('abc', PASSWORD_BCRYPT, $opt))
{
if (password_verify($password1, $hash))
echo 'password1 is valid.';
else
echo 'password1 is invalid.';
if (password_verify($password2, $hash))
echo 'password2 is valid.';
else
echo 'password2 is invalid.';
}
//结果
password1 is valid.
password2 is invalid.
检查指定的hash是否由提供的算法,可选项实现。如果不是,就认为hash需要更新。
参数列表
password_hash()
生成的hash。password_hash()
的参数一致。例子就不再自己写了,cp的php手册的例子。
<?php
$password = 'rasmuslerdorf';
$hash = '$2y$10$YCFsG6elYca568hBi2pZ0.3LDL5wjgxct1N8w/oLR/jfHsiQwCqTS';
// The cost parameter can change over time as hardware improves
$options = array('cost' => 11);
// Verify stored hash against plain-text password
if (password_verify($password, $hash)) {
// Check if a newer hashing algorithm is available
// or the cost has changed
if (password_needs_rehash($hash, PASSWORD_DEFAULT, $options)) {
// If so, create a new hash, and replace the old one
$newHash = password_hash($password, PASSWORD_DEFAULT, $options);
}
// Log user in
}
?>