captain
captain

Reputation: 1827

How to retrieve password from database with password_verify()?

I'm learning PHP and as a project I started building a social network. I did create the signup form and login form and I can add users to my database. I also hash their passwords. This is a simple site and a work in progress so there are a lot of security holes.

My problem is with the login file, I can't seem to match the user with the password he has given me. For verifying the user password I use the password_verify() function but it doesn't seem to be working right.

Here is my code:

Sign up

<?php
//signUp.php
//Here is where I add a user in my database
//I validate the input, confirm that the password is written like it  should be
//check if a user with the same username exists in the database
//if all checks out I will add the user in the database
   //and redirect the user to his profile
   require_once 'login.php';
   require_once 'helperFunctions.php';

$conn = new mysqli($servername, $username, $password, $database);

if(!$conn)
   die("Connection failed:" . mysqli_connect_error());

$myUsername = $_POST['Name'];
$myPassword = $_POST['Password'];
$myConfirm = $_POST['conPass'];

sanitize($conn, $myUsername);
sanitize($conn, $myPassword);

//check if the two passwords are the same

if($myPassword != $myConfirm){
  print "Your passwords don't match";
  header("refresh: 5; index.html");
} else {
   //check if username already exists in database
    $query = "SELECT * FROM members WHERE Username='$myUsername'";
    $result = mysqli_query($conn, $query);

    $count  = mysqli_num_rows($result);

    if($count == 0){
        //hash password
        $hashedPass = password_hash("$myPassword", PASSWORD_DEFAULT);

        //username doesn't exist in database 
        //add user with the hashed password
        $query ="INSERT INTO members (Username, Password) VALUES     ('{$myUsername}', '{$hashedPass}')";
        $result = mysqli_query($conn, $query);

        if(!$result)
            die("Invalid query: " . mysqli_error());
        else{
            print "You are now a member or The Social Network";
            header("refresh: 5; login_success.php");
        }

    } else {
        print "Username already exists";
        header("refresh: 5; index.html");
    }

}
?>

Login

<?php
//checkLogin.php
//Here is where I authenticate my users and if successfull I will show  them their profile
require_once 'login.php';
require_once 'helperFunctions.php';

$conn = new mysqli($servername, $username, $password, $database);

if(!$conn)
    die("Connection failed:" . mysqli_connect_error());

//Values from form
$myUsername = $_POST['Name'];
$myPassword = $_POST['Password'];

//sanitize input
sanitize($conn, $myUsername);
sanitize($conn, $myPassword);

$query = "SELECT * FROM members WHERE Username='$myUsername'";
$result = mysqli_query($conn, $query);
$count = mysqli_num_rows($result);

if($count == 1){
    $row = mysqli_fetch_array($result, MYSQLI_ASSOC);
    print "hashedPass = ${row['Password']}";
    print "myPassword: " . $myPassword;
    if(password_verify($myPassword, $row['Password'])){
        print "Password match";
    } else
        print "The username or password do not match";
} 
?>

Sanitize function

    function sanitize($conn, $val){
    $val = stripslashes($val);
    $val = mysqli_real_escape_string($conn, $val);
}

By running the program print "hashedPass = ${row['Password']}"; prints out the hashed password which is the same with the one I have on my database but for some reason I get redirected to the print "The username or password do not match"; statement after this.

Upvotes: 3

Views: 5106

Answers (1)

Funk Forty Niner
Funk Forty Niner

Reputation: 74217

Comment pulled and taken from a deleted answer:

"I remembered that when I first created the database I used CHAR(10) for the passwords while the hashed password needs more characters."

so the almighty answer here is that your password column is 50 characters short.

password_hash() creates a 60 characters string.

the manual states that it is best to use VARCHAR and with a length of 255 in order to accommodate for future changes.

the solution to this now, is to start over with a new registration and then login again using what you are presently using.

Example from the manual:

<?php
/**
 * We just want to hash our password using the current DEFAULT algorithm.
 * This is presently BCRYPT, and will produce a 60 character result.
 *
 * Beware that DEFAULT may change over time, so you would want to prepare
 * By allowing your storage to expand past 60 characters (255 would be good)
 */
echo password_hash("rasmuslerdorf", PASSWORD_DEFAULT)."\n";
?> 

The above example will output something similar to:

$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

Also from the manual:

Caution Using the PASSWORD_BCRYPT for the algo parameter, will result in the password parameter being truncated to a maximum length of 72 characters.

PASSWORD_DEFAULT - Use the bcrypt algorithm (default as of PHP 5.5.0). Note that this constant is designed to change over time as new and stronger algorithms are added to PHP. For that reason, the length of the result from using this identifier can change over time. Therefore, it is recommended to store the result in a database column that can expand beyond 60 characters (255 characters would be a good choice).

PASSWORD_BCRYPT - Use the CRYPT_BLOWFISH algorithm to create the hash. This will produce a standard crypt() compatible hash using the "$2y$" identifier. The result will always be a 60 character string, or FALSE on failure.
Supported Options:

Another comment/question pulled from the deleted answer:

"Can I alter my password field without having to delete my table and start from the beginning?"

The answer is yes. See this Q&A on Stack:

You can also consult:

Sidenote: You will still need re-enter new hashes for the (old) affected column(s).

Plus, as already stated; you are open to SQL injection. Use a prepared statement:

Upvotes: 3

Related Questions