0
votes

My PHP app/database setup requires hashing and dehashing of passwords. While password_hash() appears to provide proper output to the database, comparing the stored hash to the plaintext password using password_verify() provides a FALSE result.

Basic input form (signup_form) or (login_form):

<form action="sign_verify.php" method="post">
    <input id="email_add" class="field" type="text" placeholder="Email" name="email"><br>
    <input id="password" class="field" type="text" placeholder="Password" name="pword"><br>
    <input type="submit" value="Sign Up">
</form>

Hashing and adding to database (signup_verify):

$temail=trim(filter_input(INPUT_POST, 'email', FILTER_SANITIZE_STRING));
$tpword=trim(filter_input(INPUT_POST, 'pword', FILTER_SANITIZE_STRING));
if (!filter_var($temail, FILTER_VALIDATE_EMAIL)) {
    echo "Invalid email address";
}
else {
    $link = array("Database"=>dbName, "UID"=>userName, "PWD"=>userPassword, "MultipleActiveResultSets"=>true);      
    sqlsrv_configure('WarningsReturnAsErrors', 0);
    $link = sqlsrv_connect(serverName, $link);
    if($link === false){
        echo "Connection Failed.<br>";
        die( print_r( sqlsrv_errors(), true));
    }
    else{
        $hpword=password_hash($tpword, PASSWORD_DEFAULT);
        $insertSql = "INSERT INTO Card_score_storage.dbo.customer_cards (Email,Password) VALUES (?,?)";
        $params = array(&$temail,&$hpword);
        $prepareStatement = sqlsrv_prepare($link, $insertSql, $params);
        if ($prepareStatement === false) {
            echo "Looks like something went wrong.";
            echo "<br>";
           die(FormatErrors( sqlsrv_errors() )); 
        }
        else {
            if (sqlsrv_execute($prepareStatement) === false) {
            echo "Looks like something went wrong.";
            echo "<br>";
            die( print_r( sqlsrv_errors(), true));
        }
        else{
            echo "You have successfully signed up with the email: $temail <br>";
            echo "<a href='index.php'>Return to our main page</a>";
        }

Password_verify() validation after user logs in (login_verify):

require_once 'config.php';
error_reporting(E_ALL);

$email=trim(filter_input(INPUT_POST, 'email', FILTER_SANITIZE_STRING));
$pword=trim(filter_input(INPUT_POST, 'pword', FILTER_SANITIZE_STRING));

//Connect to user database
$link = array("Database"=>dbName, "UID"=>userName, "PWD"=>userPassword, "MultipleActiveResultSets"=>true);      

//Check for connection error
sqlsrv_configure('WarningsReturnAsErrors', 0);

$link = sqlsrv_connect(serverName, $link);
if($link === false){
    echo "Connection Failed.<br>";
    die( print_r( sqlsrv_errors(), true));
}
else{
    sleep(0.2);
    $LoginFetchSql= "SELECT Email,Password FROM Card_score_storage.dbo.customer_cards WHERE Email = '$email'";
    $stmt_l=sqlsrv_query($link,$LoginFetchSql);    
    $getuser = sqlsrv_fetch_array( $stmt_l, SQLSRV_FETCH_ASSOC);

    if ($getuser["Email"] ==NULL) {
        echo '<p style="text-align:center">You did not login successfully.</p>';
        session_destroy();
    }
    else{
        echo $getuser["Password"],"<br>";
        $verify=password_verify($pword,$getuser["Password"]);
        if($verify){
            echo"Good password.";   
        }
        else{
            echo"Bad Password.";
        }
    }

}

The DB column storing hashed passwords is a NCHAR of size 255. Replacing the filtered/trimmed input with direct POST values, as in $_POST["pword"] provides the same result.

1
share value of ` $getuser` ? - Niklesh Raut
Using an email of "[email protected]" and a password of "test": Array ( [Email] => [email protected] [Password] => $2y$10$f2cLGYqlLQf6gniX7JyhvOaSIQANy8qIkmLcly/0wBxdcYFLTxs8m ) - cavanaugh
are you sure about $pword value that you are passing same as you stored in DB ? - Niklesh Raut
You are checking right : check this - eval.in/739183 - Niklesh Raut
I know if you put password test directly it will work : eval.in/739202, I think you have problem here $verify=password_verify($pword,$getuser["Password"]); - Niklesh Raut

1 Answers

0
votes

I think your problem occurs when writing/retrieving from the database. I recommend var_dumping the passwords on register and when you're retrieving it and comparing those to each other.

EDIT: Changing nchar to varchar should fix it. It's because NCHAR can store unicode data (which perhaps caused the verify to return false) and has a fixed length. VARCHAR cannot store unicode data and has a variable length.

For reference check out this Stackoverflow question for more information: What is the difference between char, nchar, varchar, and nvarchar in SQL Server?