php password_verify 不适用于数据库

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27610403/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 23:26:02  来源:igfitidea点击:

php password_verify not working with database

phpmysqlmysqlipasswordspassword-protection

提问by Cbas

I am using php 5.4 with this backwards compatibility script: https://github.com/ircmaxell/password_compat/blob/master/lib/password.php

我将 php 5.4 与这个向后兼容脚本一起使用:https: //github.com/ircmaxell/password_compat/blob/master/lib/password.php

that shouldn't matter though, because I can get the hashing and verification process working in my registration function:

不过这无关紧要,因为我可以在我的注册功能中进行散列和验证过程:

$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
passwordy$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYSsuccess

but whenever I try to store the hash in a MySQL database and then retrieve it for the verify function, it always fails. Here is my login function:

但是每当我尝试将哈希存储在 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
passwordy$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYSfailure

My 'password' column has this datatype: VARCHAR(255) NOT NULL

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

No php errors show up so the only thing I can think of is that the hash value is not formatted in the same way when it comes out of the database as when it went in, but when I echo out the values, they appear to be identical.

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

How else can I debug this / what is wrong with my code?

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

Thanks

谢谢

UPDATE:

更新:

This definitely has something to do with encoding:

这肯定与编码有关:

$hardcode_hash = 'y$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS';

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

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

//OUTPUT
y$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS
y$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS
failure

how do I reformat the SQL value to match the output of password_hash? Here's what I've tried:

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

(string)$hash
utf8_encode($hash)

if I do:

如果我做:

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

if($hash == $hardcode_hash)returns true, but password_verify($pass, $hash)still returns false

if($hash == $hardcode_hash)返回真,但password_verify($pass, $hash)仍然返回假

回答by Cbas

Found the problem. when I did this:

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

echo strlen($hash)

it printed 90, which is strange because there were definitely no spaces at the end when I printed out the success/failure message, and the field has a varchar length of 255

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

I added this line:

我添加了这一行:

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

And now it works fine.

现在它工作正常。

Its strange that no one else seems to have run into this issue. There are similar posts about password_verify, but none of them required this type of conversion, or any conversion for that matter:

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

php password_verify not working

php密码验证不起作用

password_verify php not match

password_verify php 不匹配

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

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

Using PHP 5.5's password_hash and password_verify function

使用 PHP 5.5 的 password_hash 和 password_verify 函数

One thing that bothers me is this prevents the code from being forward compatible. How will I know that the hash is 60 characters long when the default changes?

困扰我的一件事是这会阻止代码向前兼容。当默认值更改时,我如何知道散列长度为 60 个字符?

回答by MosesK

I was having the same issue with password_verify(). For me i had declared my username and password as VARCHAR(50). Therefore it was not inserting the hash value in my database which is obviously more than 50 characters. Therefore every time I used password_verify() I got a false. I changed my database values to varchar(255). Inserted data again, tested and it works.

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

回答by Kobus

Just for future reference. I had the same issue with passwords failing for no reason. When I took a closer look at it I saw that the password field in the database was not big enough to store the full hash so some characters were cut off. After increasing the size of the database field it worked perfectly.

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

回答by Lexix

I had the same issue you had with it not working, for some reason it seems to help putting the:

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

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

into the code although my string was already 60 characters long.

尽管我的字符串已经有 60 个字符长,但还是输入了代码。

回答by DBC

I had the same issue and it was still not working despite ensuring my database columns were varchar(255), that the hashes were 60 characters, and ensuring my encoding was UTF-8 all the way through. I'm pretty new to PHP and SQL so I won't pretend to understand exactly why it worked, but I managed to fix it so I hope this post will help other folks with the same problem.

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

It turned out that the underlying reason password_verify() wasn't verifying my hashes was because I had made a prepared statement that used a stored procedure earlier in the script without fetching all the results from the query properly to clear the buffer, before closing and reopening the connection to perform the next query. Calling next_result() on the mysqli_link after closing the statement will make sure any results are consumed.
Additionally, I was then using another prepared statement with a stored procedure to make the insert for the password, but I still needed to make calls to store_result() and free_result() even though no result sets were returned from the insert. I'm assuming the combination of these things was corrupting my data somewhere along the line, resulting in password_verify() returning false on seemingly identical hashes.

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

This answerwas for a different problem but I found it useful for learning how to properly close out prepared statements with stored procedures.

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