2

My webpage starts with a login page, like many, and if the user has no account they can sign up. My sign up works and the users password they input is successfully hashed with password_hash and sent to the database. However, when trying to login, password_verify always returns false. Thinking I made a silly error when I originally made the hashed password, I echoed the variable I was using as the second parameter in password_verify. However, it was an exact match to the hash in the database. What could be the issue?? Shortened code is available below for both creating the password during sign up and checking the password while logging in.

CREATING HASHED PASSWORD

<?php
    session_start();
    require('db_credentials.php');

    $inputUsername = $_POST['createUsername'] ? $_POST['createUsername'] : null;
    $inputPassword = $_POST['createPassword'] ? $_POST['createPassword'] : null;
    $vPassword = $_POST['verifyPassword'] ? $_POST['verifyPassword'] : null;

     //protect database from corrupt user input
    $inputUsername = $mysqli->real_escape_string($inputUsername);
    $inputPassword = $mysqli->real_escape_string($inputPassword);
    $vPassword = $mysqli->real_escape_string($vPassword);

    //create connection
    $mysqli = new mysqli($servername, $username, $password, $dbname);

    $protectedPassword = password_hash($inputPassword, PASSWORD_DEFAULT);

    //Check if the passwords match
if($inputPassword != $vPassword){
    echo '<p style = "text-align: center;">Oops!The passwords you input did not match. Please try again.</p>';
    session_write_close();
    exit;
}

//Check for duplicate username
$query = "SELECT * FROM user_info WHERE username = ' ".$inputUsername." ' ";
$result = mysqli_query($mysqli, $query);

if(mysqli_num_rows($result) == 1) {
    echo '<p style = "text-align: center;">Oops! That Username is already taken. <br>Please try a different one.</p>';    
    session_write_close();
    exit;
}
//Username is not takin and the passwords match
else {
    $sql = "INSERT INTO user_info (username, password) VALUES (' ".$inputUsername." ', ' ".$protectedPassword." ')";
    echo '<p style = "text-align: center;">Success! You Have Made an Account!</p>';
    if($mysqli->query($sql) === TRUE) {
        session_write_close();
        exit;
    }
     else {
         echo "Error: " . $sql . "<br>" . $conn->error;
    }
}
?>

LOGGING IN

<?php

    require('db_credentials.php');

    $inputUsername = $_POST['username'] ? $_POST['username'] : null;
    $inputPassword = $_POST['password'] ? $_POST['password'] : null;
    //protect database from corrupt user input
    $inputUsername = $mysqli->real_escape_string($inputUsername);
    $inputPassword = $mysqli->real_escape_string($inputPassword);

    $mysqli = new mysqli($servername, $username, $password, $dbname);        

    $query = "SELECT * FROM user_info WHERE username = ' ".$inputUsername." ' ";
    $result = $mysqli->query($query);

    //check if username is in database. If it is, do the passwords match?
    if($result->num_rows === 1) {

        $row = $result->fetch_array(MYSQLI_ASSOC);
        echo $row['password'] . "<br>"; //matches hash in database exactly
        echo $inputPassword; //matches the password I type in. Which is same I used to sign up.
        if(password_verify($inputPassword, $row['password'])){
            header("Location: puzzlerMember.php"); //this never happens
            exit; 
        }

    }    
    echo '<p style = "text-align: center;">Oops! Your Username/Password is incorrect. Sign up if you do not have an account.</p>'; //this always happens
    exit;

?>

Note: In the database, I have the password column set to VARCHAR(255). I've looked at many of these questions which are similar, but they all seemed to have mistaken the length of their password in the database to be too short. If they did not, I tried the top answer of the solutions. I have absolutely no idea what is wrong. If you can help, I thank you in advance.

1 Answers1

2

You are escaping your password, as a result this changes the password from what it was. Instead of relying on escaping as a security measure (which in itself is a misconception), use prepared statements.

As per the comment below, a clarification is required it seems: You are escaping the password then hashing it, as a result what is stored in the db is not what the user passes therefore it will never find what the user passes, hence, false is always returned.

Related: Should I mysql_real_escape_string the password entered in the registration form?

Update #1

As spotted by @mario, you seem to have spaces in your query when you are passing the values to it as such, it is searching your table for incorrect values.

Reading Material

Prepared Statements

Script47
  • 14,230
  • 4
  • 45
  • 66
  • I think the point you need to emphasize is that the password is being escaped *before* it is hashed. MySQL does not get the password, it gets the hash of that password, so any characters that you are escaping before hashing will become the password itself. – Mike Jun 16 '18 at 23:38
  • @Mike I have clarified that part. Thanks for the feedback. – Script47 Jun 16 '18 at 23:41
  • Please reread your sign up code, you assign `$protectedPassword` the value of `$inputPassword` which is escaped and then you hash it and yes, the problem is the sign up. – Script47 Jun 16 '18 at 23:54
  • 2
    Are we sure this is relevant? Pre-escaping the password is misguided, of course. But at least it's consistent in also being misapplied for the hash verification. And even then, what are the chances that the input password contains any quotes? // Looks more like the extra spaces around username and hash might be problematic. – mario Jun 17 '18 at 00:00
  • 1
    I got rid of the escaping, as for when I checked @Script47's link, it was nonsensical and should never be used for passwords. However, after removing it, I still get that `password_verify` returns false. – Christian Caldwell Jun 17 '18 at 00:08
  • @mario excellent spot regarding the space issue. Updated my answer. Thanks. – Script47 Jun 17 '18 at 00:09
  • @mario I do not understand. Maybe I've been looking at this code too long today but I don't see a spacing issue. Is it within the creating hashed password or logging in section? Sorry guys. I appreciate it. – Christian Caldwell Jun 17 '18 at 00:18
  • `"INSERT INTO user_info (username, password) VALUES (' ".$inputUsername." ', ' ".$protectedPassword." ')"` - You have a space before and after the username and password. Even though this is incorrect, the username will work because you're also `SELECT`ing with the extra spaces in your other query, however the `password_verify` method will not validate, because you are essentially doing `password_verify($password, {SPACE}$hash{SPACE})`. As @Script47 said in the answer, use prepared statements with bound parameters. – Mike Jun 17 '18 at 00:38
  • Ohhh Myyyyyy. Really? Simple spacing issues have caused this many hours of frustration? It works now and the login is successful. I owe you guys big time! Thank you for the help. I appreciate it more then you'll know. I'll look into using prepared statements as this is not the first time i've heard it is the way to go. – Christian Caldwell Jun 17 '18 at 00:48
  • On another note, since you're just doing the authentication now I'm assuming you're just getting started. Have you thought about using a framework to handle this for you? Trying to roll your own authentication is not only reinventing the wheel, you are very prone to make mistakes without even realizing it. – Mike Jun 17 '18 at 00:48
  • @Mike I had no idea there was a framework to handle authentication. I imagine that makes life a lot more simple. I just started html and php as of last semester at school, so we learned bare bones and I decided to tackle a login page on my own after the semester. I'll have to look it up. Thanks! – Christian Caldwell Jun 17 '18 at 00:56
  • @ChristianCaldwell I know it's at least super easy in Laravel. I don't have experience with other frameworks though. Just execute literally 1 command and you get a bare bones site with registration, login and password reset. – Mike Jun 17 '18 at 01:06
  • @Mike. Appreciate the name of the framework and am looking forward to checking it out. Thanks! – Christian Caldwell Jun 17 '18 at 01:18