web-dev-qa-db-ja.com

php password_verifyがデータベースで機能しない

この下位互換性スクリプトで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
_

password_hashの出力と一致するようにSQL値を再フォーマットするにはどうすればよいですか?これが私が試したものです:

_(string)$hash
utf8_encode($hash)
_

私が行った場合:

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

if($hash == $hardcode_hash)はtrueを返しますが、password_verify($pass, $hash)は引き続きfalseを返します

14
Cbas

問題が見つかりました。私がこれをしたとき:

echo strlen($hash)

成功/失敗のメッセージを出力したときに最後にスペースがまったくないため、フィールドがvarcharの長さが255であるので、90と出力されました。

私はこの行を追加しました:

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

そして今それはうまく働きます。

他の誰もこの問題に遭遇していないように見えるのは奇妙です。 password_verifyに関する同様の投稿がありますが、このタイプの変換や、そのための変換は必要ありません。

php password_verify not working

password_verify phpが一致しません

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

PHP 5.5のpassword_hashおよびpassword_verify関数を使用

気になるのは、これがコードの上位互換性を妨げていることです。デフォルトが変更されたときに、ハッシュが60文字であることをどのようにして知ることができますか?

12
Cbas

Password_verify()で同じ問題が発生していました。私のために、自分のユーザー名とパスワードをVARCHAR(50)と宣言しました。したがって、明らかに50文字を超えるハッシュ値をデータベースに挿入していませんでした。したがって、password_verify()を使用するたびに、falseが発生しました。データベースの値をvarchar(255)に変更しました。データを再度挿入し、テストすると機能します。

4
MosesK

将来の参考のために。理由もなくパスワードが失敗するという同じ問題がありました。よく見ると、データベースのパスワードフィールドはハッシュ全体を格納するのに十分な大きさではないため、一部の文字が切り捨てられていました。データベースフィールドのサイズを増やした後、完全に機能しました。

3
Kobus

私はあなたがそれが機能していないのと同じ問題を抱えていました、何らかの理由でそれを置くのに役立つようです:

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

文字列はすでに60文字でしたが、コードに挿入しました。

2
Lexix

私は同じ問題を抱えていましたが、データベースの列がvarchar(255)であり、ハッシュが60文字であり、エンコーディングがUTF-8であることを確認しても、それでも機能しませんでした。私はPHPとSQLにかなり慣れているので、なぜそれが機能したのか正確に理解するふりはしませんが、どうにか修正できたので、この投稿が同じ問題を持つ他の人々の助けになることを願っています。

Password_verify()がハッシュを検証しなかった根本的な理由は、閉じる前に、クエリからすべての結果を適切にフェッチせずにバッファからクリアすることなく、スクリプトの前半でストアドプロシージャを使用する準備済みステートメントを作成したためです。接続を再度開いて次のクエリを実行します。ステートメントを閉じた後、mysqli_linkでnext_result()を呼び出すと、結果が確実に消費されます。
さらに、ストアドプロシージャで別の準備済みステートメントを使用してパスワードの挿入を行いましたが、結果セットが返されなかった場合でも、store_result()およびfree_result()を呼び出す必要がありました。インサート。これらの組み合わせにより、データが行のどこかで破損し、password_verify()が一見同一のハッシュでfalseを返したと想定しています。

この回答 は別の問題に対するものでしたが、ストアドプロシージャで準備されたステートメントを適切に閉じる方法を学ぶのに役立ちました。

1
DBC