php password_verify 不适用于数据库 [重复]

Posted

技术标签:

【中文标题】php password_verify 不适用于数据库 [重复]【英文标题】:php password_verify not working with database [duplicate] 【发布时间】:2015-02-21 00:11:03 【问题描述】:

我正在使用带有向后兼容性脚本的 php 5.4:https://github.com/ircmaxell/password_compat/blob/master/lib/password.php

但这不重要,因为我可以在我的注册函数中进行散列和验证过程:

$hash = password_hash($pass, PASSWORD_DEFAULT);

echo $pass;
echo $hash;

if( password_verify($pass,$hash) )
    echo 'success';
else echo 'failure';

//success is always shown

//EXAMPLE INPUT
$pass = 'password';

//EXAMPLE OUTPUT
password$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYSsuccess

但每当我尝试将哈希存储在 mysql 数据库中,然后为验证函数检索它时,它总是失败。这是我的登录功能:

function user_login( $mysqli, $email, $pass )    

        $err_msg = 'login: '.$mysqli->error.' | '.$email;

        if( $stmt = $mysqli->prepare('SELECT password FROM users WHERE email=?') ) :

            if( !$stmt->bind_param('s', $email) ) log_sql_error( $err_msg );
            if( !$stmt->execute() ) log_sql_error( $err_msg );
            if( !$stmt->bind_result( $hash ) ) log_sql_error( $err_msg );
            if( $stmt->fetch() === FALSE ) log_sql_error( $err_msg );
            if( !$stmt->close() ) log_sql_error( $err_msg );

            //I can see that these values are identical to the ones
            //echoed out in the registration function
            echo $pass;
            echo $hash;

            if( password_verify($pass,$hash) )
                echo 'success';
            else echo 'failure';

        else : log_sql_error( $err_msg );
        endif;

//failure is always shown

//EXAMPLE INPUT
$pass = 'password';

//EXAMPLE OUTPUT
password$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYSfailure

我的“密码”列具有以下数据类型:VARCHAR(255) NOT NULL

没有出现 php 错误,所以我唯一能想到的是哈希值从数据库中出来时的格式与进入时的格式不同,但是当我回显这些值时,它们看起来是一样的。

我还能如何调试这个/我的代码有什么问题?

谢谢

更新:

这肯定和编码有关:

$hardcode_hash = '$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS';

echo $hash;
echo '<br/>';
echo $hardcode_hash;
echo '<br/>';

if( $hash == $hardcode_hash )
    echo 'success';
else echo 'failure';

//OUTPUT
$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS
$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS
failure

如何重新格式化 SQL 值以匹配 password_hash 的输出?这是我尝试过的:

(string)$hash
utf8_encode($hash)

如果我这样做:

$hash = settype($hash,"string");

if($hash == $hardcode_hash) 返回 true,但 password_verify($pass, $hash) 仍然返回 false

【问题讨论】:

谁在不发表评论或答案的情况下对问题投了反对票?没有帮助... 这些天大部分时间都是这样 :-) 您可以展示示例 $pass$hash 输出。没有人能够测试运行您的代码摘录。 使用var_dump。如果字符串真的相同,则在第二种情况下不可能失败。 您是否检查了您的页面/数据库的编码,是否有可能一个变量包含多字节字符串,而另一个不包含? 【参考方案1】:

发现问题。当我这样做时:

echo strlen($hash)

它打印了 90,这很奇怪,因为当我打印出成功/失败消息时,最后肯定没有空格,并且该字段的 varchar 长度为 255

我添加了这一行:

$hash = substr( $hash, 0, 60 );

现在它可以正常工作了。

奇怪的是,似乎没有其他人遇到过这个问题。有关于 password_verify 的类似帖子,但没有一个需要这种类型的转换,或任何与此相关的转换:

php password_verify not working

password_verify php not match

http://forums.phpfreaks.com/topic/283407-need-help-with-password-verify/

Using PHP 5.5's password_hash and password_verify function

困扰我的一件事是这会阻止代码向前兼容。当默认值更改时,我怎么知道哈希是 60 个字符长?

【讨论】:

这真的没有必要。您确定它是 varchar 字段而不是 char* 吗?也许您也可以看看这个关于使用 UTF-8 进行 Php(编码)和数据库(字符集)的小 article。将哈希插入数据库的代码也可能很有趣。 添加到@martinstoeckli 的输入,数据库中的哈希密码字段最好使用CHAR 数据类型,并在使用PASSWORD_BCRYPT 常量时将其长度设置为60。在这种情况下,哈希值将始终为 60 个字符。 您与其他解决方案的链接让我找到了答案。谢谢!具体来说,是“password_verify not working”导致我找到我的解决方案。 @Cbas 我遇到了同样的问题。我尝试了 trim($hash) 而不是 substr() 并且它有效!【参考方案2】:

我在使用 password_verify() 时遇到了同样的问题。对我来说,我已将我的用户名和密码声明为 VARCHAR(50)。因此,它没有在我的数据库中插入显然超过 50 个字符的哈希值。因此,每次我使用 password_verify() 时,我都会得到一个错误。我将数据库值更改为 varchar(255)。再次插入数据,测试成功。

【讨论】:

我遇到了同样的问题。很高兴你发表评论!谢谢。【参考方案3】:

仅供日后参考。我遇到了同样的问题,密码无缘无故失败。当我仔细查看它时,我发现数据库中的密码字段不够大,无法存储完整的哈希,所以有些字符被截断了。增加数据库字段的大小后,它工作得很好。

【讨论】:

【参考方案4】:

我遇到了同样的问题,它无法正常工作,出于某种原因,它似乎有助于放置:

$hash = substr( $hash, 0, 60 );

进入代码虽然我的字符串已经有 60 个字符长。

【讨论】:

【参考方案5】:

我遇到了同样的问题,尽管确保我的数据库列是 varchar(255)、哈希是 60 个字符并且确保我的编码一直是 UTF-8,但它仍然无法正常工作。我对 PHP 和 SQL 还很陌生,所以我不会假装完全理解它的工作原理,但我设法修复了它,所以我希望这篇文章能帮助其他有同样问题的人。

事实证明,password_verify() 没有验证我的哈希值的根本原因是因为我在脚本的前面做了一个准备好的语句,它使用了一个存储过程,而没有正确地从查询中获取所有结果来清除缓冲区,在关闭并重新打开连接以执行下一个查询之前。关闭语句后在 mysqli_link 上调用 next_result() 将确保使用任何结果。 此外,然后我使用另一个带有存储过程的准备好的语句来插入密码,但我仍然需要调用 store_result() 和 free_result(),即使插入没有返回结果集。我假设这些东西的组合在某处破坏了我的数据,导致 password_verify() 在看似相同的哈希值上返回 false。

This answer 是针对不同的问题,但我发现它对于学习如何使用存储过程正确关闭准备好的语句很有用。

【讨论】:

以上是关于php password_verify 不适用于数据库 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

使用 PHP 5.5 的 password_hash 和 password_verify 函数

password_verify 不验证哈希

PHP password_verify() 与 Python bcrypt.hashpw()

PHP password_verify 不能与准备好的语句一起使用

password_verify不验证哈希

为啥 password_verify 返回 false?