为什么 password_verify 返回 false?

7

我正在使用password_verify来检查我的哈希密码。我使用的是PHP 5.5版本:

// get result row (as an object)
$result_row = $result_of_login_check->fetch_object();

// using PHP 5.5's password_verify() function to check if the provided password fits
// the hash of that user's password
if (password_verify($_POST['user_password'], $result_row->user_password_hash)) {
    // ...
}

password_verify中我得到了false。我已经检查了帖子的值和mysql user_password_hash返回值。

我不知道为什么它会返回false。

有任何想法吗?


1
你是否使用 password_hash 来创建密码? - b.b3rn4rd
是的,$user_password = $_POST['user_password_new'];$user_password_hash = password_hash($user_password, PASSWORD_DEFAULT); - Lucca Zenobio
4个回答

24
可能问题出在你的列长度上,根据手册上的说法: 建议将结果存储在一个可以超过60个字符的数据库列中(255个字符是一个不错的选择)。link

1
最好在数据库中使用CHAR数据类型来存储哈希密码字段,并将其长度设置为60,使用PASSWORD_BCRYPT常量。这样,哈希值始终为60个字符长。 - Ashesh
我遇到了一个问题:当我在HTML上生成密码哈希时,我总是复制了一个带有空格的结尾,所以它从未起作用。 - João Pedro Schmitz

12

有很多原因会导致password_verify返回false,从表格设置到密码比较都可能会出现问题。以下是常见的失败原因:

列设置

  • 您的表中密码列的长度过短:

    • 如果您使用PASSWORD_DEFAULT,则建议将结果存储在可以扩展超过60个字符的数据库列中(255个字符是一个不错的选择)。
    • 如果您使用PASSWORD_BCRYPT,则建议将结果存储在一个60个字符的数据库列中,因为PASSWORD_BCRYPT始终会生成一个60个字符的字符串或在失败时生成FALSE。

密码清理

另一个常见原因是开发人员试图“清理”用户的密码以防止其恶意使用,结果导致输入与存储在表中的内容不同。甚至不需要转义输入,应该使用准备好的语句。您甚至不应该trim密码,因为这可能会改变最初提供的内容。

密码验证

使用password_verify时,您需要将明文密码与数据库中的哈希值进行比较,而不是比较哈希值(这意味着您需要在用户注册时存储用户的哈希密码):

<?php

$hashed = password_hash('test', PASSWORD_DEFAULT);
$password = 'test';

if (password_verify($password, $hashed)) {
  echo 'success';
} else {
  echo 'fail';
}

?>

Repl

硬编码密码

如果您正在使用硬编码的哈希值并且遇到问题,请确保在将该值存储在变量中时使用单引号而不是双引号,因为使用双引号时$会被解释:

<?php
// Undefined variable: QHpfI0MfQWjvsVQWRdFHSOX6WqG8LSf0iFGiKs0Fz0RvqhpFOpAKu :1
$incorrect = "$2y$10$QHpfI0MfQWjvsVQWRdFHSOX6WqG8LSf0iFGiKs0Fz0RvqhpFOpAKu";

$correct = '$2y$10$QHpfI0MfQWjvsVQWRdFHSOX6WqG8LSf0iFGiKs0Fz0RvqhpFOpAKu';
?>

Repl - 分别注释掉。

附录

根据文档:

注意 强烈建议您不要为此函数生成自己的盐。如果您未指定盐,则它将自动为您创建一个安全的盐。

如上所述,在PHP 7.0中提供salt选项将生成停用警告。在将来的PHP版本中,可能会删除手动提供盐的支持。


1
简单的调试步骤:
  1. 在注册阶段,打印出并记录原始密码和哈希值的确切数值。类似于:

     var_dump($password);
     $hash = password_hash($password, PASSWORD_DEFAULT);
     var_dump($hash);
    

    然后将输出内容复制并粘贴到某个文本文件中。

  2. 在登录阶段,打印出并记录提供的密码和从数据库返回的哈希值的确切数值。类似于:

     var_dump($password);
     var_dump($row['password']);
     if(password_verify($password, $row['password'])) ...
    
然后只需比较这些值。如果password_verify()失败,那么原始密码或哈希值不匹配。如果原始密码不匹配,则输入的密码要么是错误的,要么在某些无用的“清理”过程中被破坏了。如果从数据库返回的哈希值不匹配,则要么是在某些无用的“清理”过程中被破坏了,要么是由于数据库中的列属性不正确而发生了更改。

0

检查参数顺序

只是想指出一些发生在我身上的事情,我曾经阅读过这个主题,试图在几分钟前解决我的问题,并可以帮助您解决问题。
请检查您是否按正确顺序提供了password_verify()函数的参数:

password_verify(string $password, string $hash)

$password是通过post或其他方法接收且正在尝试验证的密码。

$hash是您要将密码与之比较的哈希值。(例如存储在您的数据库中的密码哈希)

我曾经犯了一个错误,就是颠倒了参数的顺序,因此结果并不像我预期的那样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接