首页 > 解决方案 > password_verify - 密码与哈希不匹配

问题描述

我有一个登录系统。您可以注册一个用户并稍后登录(在这种情况下,password_verify 完成了它的工作)。然后我有一个密码恢复系统。您会收到一封电子邮件,其中包含带有令牌等的链接。您更改密码并在数据库中更改(我可以通过更改的哈希看到它)。然后,如果您尝试使用新密码登录,它会显示密码错误,旧密码也不会。

/// new password is set
$newPwdHash = password_hash($pwd, PASSWORD_DEFAULT);
mysqli_stmt_bind_param($stmt, 'ss', $newPwdHash, $tokenEmail);
mysqli_stmt_execute($stmt);
$pwdCheck = password_verify($pwd, $row['pwdUsers']);

我不知道它是否有帮助,但是如果您在恢复密码时尝试设置的不是散列密码,而是通常的密码,它会在数据库中将其更改为空的空白 idk 为什么。

图 1 图 2

//login
if (isset($_POST['login'])) {
    require 'db.inc.php';
    $mailuid = $_POST['mailuid'];
    $pwd = $_POST['pwd'];    
    if (empty($mailuid) || empty($pwd)) {
        header('Location: ../index.php?error=empty');
        exit();
    } else {
        $sql = 'SELECT * FROM users WHERE uidUsers=? OR emailUsers=?';
        $stmt = mysqli_stmt_init($link);

        if (!mysqli_stmt_prepare($stmt, $sql)) {
            header('Location: ../index.php?error=sql');
            exit();
        } else {
            mysqli_stmt_bind_param($stmt, 'ss', $mailuid, $mailuid);
            mysqli_stmt_execute($stmt);
            $result = mysqli_stmt_get_result($stmt);
            if ($row = mysqli_fetch_assoc($result)) {
                $pwdCheck = password_verify($pwd, $row['pwdUsers']);
                if (!$pwdCheck) {
                    header('Location: ../index.php?error=wrongpwdormail');
                    exit();
                } elseif ($pwdCheck) {
                    session_start();
                    $_SESSION['id'] = $row['idUsers'];
                    $_SESSION['uid'] = $row['uidUsers'];
                    header('Location: ../index.php?login=success');
                    exit();
                } else {
                    header('Location: ../index.php?error=wrongpwdormail');
                    exit();
                }
            } else {
                header('Location: ../index.php?error=nouser');
                exit();
            }
        }
    }
} else {
    header('Location: ../index.php');
    exit();
}

//reset
$tokenEmail = $row['pwdResetEmail'];
$sql = 'SELECT * FROM users WHERE emailUsers=?';
if (!mysqli_stmt_prepare($stmt, $sql)) {
    echo 'error2';
    exit();
} else {
    mysqli_stmt_bind_param($stmt, 's', $tokenEmail);
    mysqli_stmt_execute($stmt);
    $result = mysqli_stmt_get_result($stmt);
    if (!$row = mysqli_fetch_assoc($result)) {
        echo 'error3';
        exit();
    } else {
        $sql = 'UPDATE users SET pwdUsers=? WHERE emailUsers=?';
        if (!mysqli_stmt_prepare($stmt, $sql)) {
            echo 'error4';
            exit();
        } else {
            $newPwdHash = password_hash($pwd, PASSWORD_DEFAULT);
            mysqli_stmt_bind_param($stmt, 'ss', $newPwdHash, $tokenEmail);
            mysqli_stmt_execute($stmt);
            $sql = 'DELETE FROM pwdReset WHERE pwdResetEmail=?';
            if (!mysqli_stmt_prepare($stmt, $sql)) {
                echo 'error5';
                exit();
            } else {
                mysqli_stmt_bind_param($stmt, 's', $tokenEmail);
                mysqli_stmt_execute($stmt);
                header('Location: ../signup.php?newpwd=updated');
           }
        }
    }
 }

标签: php

解决方案


注意:除非您在登录(isset)部分之外的多个部分上复制变量,否则它很可能是未定义的,因此散列未定义的变量。所以密码永远不会匹配。

请注意您是如何在重置部分使用变量$pwd的,即使您是$pwd在“登录”部分中创建变量。如果代码的两个部分都包含在一个文件中并且顺序与您在 StackOverflow 上发布的顺序一致,我非常怀疑您是否达到了该部分。

if (isset($_POST['login'])) {
        $mailuid = $_POST['mailuid'];
        $pwd = $_POST['pwd'];
        //NOTICE: unless you are duplicating the variables on multiple parts
        //including OUTSIDE of the login (isset) part, it most likely is undefined
        //thus, hashing an undefined variable. So the password will NEVER match.
} else {
    //header('Location: ../index.php');
    //exit(); //will halt execute, so it's interesting that you're even reaching the reset part. 
    //Unless the reset part and login part aren't in the same file.
}

重置部分和登录部分是否在同一个文件中?

else {
            $newPwdHash = password_hash($pwd, PASSWORD_DEFAULT);
            mysqli_stmt_bind_param($stmt, 'ss', $newPwdHash, $tokenEmail);
            mysqli_stmt_execute($stmt);
            $sql = 'DELETE FROM pwdReset WHERE pwdResetEmail=?';
            if (!mysqli_stmt_prepare($stmt, $sql)) {
                echo 'error5';
                exit();
            } else {
                mysqli_stmt_bind_param($stmt, 's', $tokenEmail);
                mysqli_stmt_execute($stmt);
                header('Location: ../signup.php?newpwd=updated');
           }
        }

我建议您为重置部分创建一个专用页面,您可以在其中执行以下操作:

if (isset($_POST["recovery"])) { // or whatever kind of check you wish to do prior to firing your code.
$tokenEmail = $row['pwdResetEmail']; //no idea where you created this -> 
//$row["pwdResetEmail"]; I assume it's a part you're either not showing us, 
//or this isn't working either. I am guessing the first one (that you aren't 
//showing us where you retrieve it), or else it would not be possible to 
//change anything and the query should fail (correct me if I am wrong here guys).
$pwd = // NOTICE: assign the password. May it be a POST or a GET or whatever
$sql = 'SELECT * FROM users WHERE emailUsers=?';
if (!mysqli_stmt_prepare($stmt, $sql)) {
    echo 'error2';
    exit();
} else {
    mysqli_stmt_bind_param($stmt, 's', $tokenEmail);
    mysqli_stmt_execute($stmt);
    $result = mysqli_stmt_get_result($stmt);
    if (!$row = mysqli_fetch_assoc($result)) {
        echo 'error3';
        exit();
    } else {
        $sql = 'UPDATE users SET pwdUsers=? WHERE emailUsers=?';
        if (!mysqli_stmt_prepare($stmt, $sql)) {
            echo 'error4';
            exit();
        } else {
            $newPwdHash = password_hash($pwd, PASSWORD_DEFAULT); //NOTICE: 
            //NOW THE VARIABLE $PWD IS DEFINED
            mysqli_stmt_bind_param($stmt, 'ss', $newPwdHash, $tokenEmail);
            mysqli_stmt_execute($stmt);
            $sql = 'DELETE FROM pwdReset WHERE pwdResetEmail=?';
            if (!mysqli_stmt_prepare($stmt, $sql)) {
                echo 'error5';
                exit();
            } else {
                mysqli_stmt_bind_param($stmt, 's', $tokenEmail);
                mysqli_stmt_execute($stmt);
                header('Location: ../signup.php?newpwd=updated');
           }
        }
    }
 }
}

推荐阅读