我修改了我的旧帖子。我尝试了crypt()函数,现在尝试使用password_hash()和password_verify()来验证来自数据库的加密密码,但在每次调用时,password_hash()函数返回不同的加密字符串,而password_verify()无法匹配。
这就是我这样做的方式。
//please ignore the syntax error if any
$data = '11';
$dbpass = password_hash($data, PASSWORD_BCRYPT);
echo $dbpass; // displays the random strings on each page refresh.
将密码保存到数据库后,在登录过程中不会匹配。以下是我的实际功能。
private function process_data($password){
$password = __STR.$password.__STR;
return password_hash($password, PASSWORD_BCRYPT);
}
private function processed($login_password, $dbpassword){
$login_password = __STR.$login_password.__STR;
return password_verify($login_password, $dbpassword);
}
在为密码创建散列字符串的每个函数调用中,该函数下次返回不同的字符串。
答案 0 :(得分:45)
好的,让我们一个接一个地看看。
首先,它是哈希,而不是加密。加密是双向的,散列是一种方式。我们想哈希。我们从不想加密。是的,术语很重要。请使用正确的术语。
接下来,每次调用password_hash
假设都会返回不同的哈希值。那是因为它产生了强烈的随机盐。这就是它的设计方式,以及你应该如何使用它。
此外,不要执行在密码之前和之后添加__STR
的“胡椒”事情。你什么都不做,但可能会削弱用户密码(这是不好的)。如果您想了解更多关于为什么这是一个坏主意的信息:Read This Answer。
继续,我强烈建议您不要直接使用crypt
。它实际上非常容易搞砸并产生极弱的哈希值。这就是设计password_*
api的原因。 crypt
是一个低级库,您希望在代码中使用高级库。有关搞砸bcrypt的方法的更多信息,请查看我的博客:Seven Ways To Screw Up Bcrypt。
密码API旨在成为一个简单的一站式商店。如果它不起作用,请检查以下事项:
您使用的是PHP> = 5.5.0吗?或者您使用PHP> = 5.3.7与password_compat?
您的数据库列是否足够宽?
它必须至少 60个字符。
您是否在检查函数的结果是字符串,而不是bool(false)
?
如果出现内部错误,则会从password_hash
返回非字符串。
您收到任何错误吗?
您是否已将error_reporting
设置为其最大设置(我建议-1
捕获所有内容)并检查代码是否没有引发任何错误?
您确定正确使用它吗?
function saveUser($username, $password) {
$hash = password_hash($password, PASSWORD_BCRYPT);
// save $username and $hash to db
}
function login($username, $password) {
// fetch $hash from db
return password_verify($password, $hash);
}
请注意,每个人只应调用一次。
您使用的是PHP< 5.3.7与password_compat?如果是这样,这就是你的问题。您在不受支持的PHP版本上使用兼容性库。您可以使用它(某些RedHat发行版已经向后移植了必要的修复程序),但您使用的是不受支持的版本。请升级到合理的版本。
如果所有其他方法都失败了,请尝试运行此代码并报告输出:
$hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
$test = crypt("password", $hash);
$pass = $test == $hash;
echo "Test for functionality of compat library: " . ($pass ? "Pass" : "Fail");
echo "\n";
如果返回Fail
,则表示您运行的是不受支持的PHP版本,应该进行升级。如果它返回pass,则错误在逻辑中的某处(库正常运行)。
答案 1 :(得分:1)
存储密码的最佳方法是使用PHP的函数password_hash()。它会自动为每个密码生成一个加密安全的salt,并将其包含在生成的60个字符的字符串中。你根本不用担心盐!
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
你自己的方案非常弱,首先你使用MD5这种方法太快而无法生成密码哈希,然后你使用静态盐,这会破坏盐的目的。也许你想看一下我关于safely storing passwords的教程。
编辑以回答更新的问题:
没有必要将__STR
添加到密码中(如果你想添加辣椒有更好的方法),但你的示例函数应该实际工作。由于随机盐,password_hash()
的返回值每次都会不同。这是正确的,函数password_verify()
能够提取此盐以进行验证。在您的情况下,数据库字段可能是问题。确保它可以容纳60个字符的字符串。