• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 923
  • Last Modified:

password_verify issues

I am trying to log in using the username and password I signed up with but I just keep getting my "no user found" message so it clearly isn't working but I don't know why.

      
$password = $link->real_escape_string($_POST['password']);
		$email = $link->real_escape_string($_POST['email']);
		
		$sql = "SELECT password, userID FROM `users` WHERE email = '$email' LIMIT 1";
		$result = $link->query($sql);
		if ($result->num_rows == 1) {
		$row = $result->fetch_assoc();
		$db_password = $row["password"];
		if(password_verify($password, $db_password)) {
			
			echo "correct";
			
			} else {
			
			echo "no user found";
			}
		}

Open in new window


I used this to create my password on my register page:

$password = trim(password_hash($password, PASSWORD_BCRYPT, [12]));

Open in new window

0
Black Sulfur
Asked:
Black Sulfur
  • 9
  • 6
1 Solution
 
Ray PaseurCommented:
Have you tried printing out the values in $password and $db_password and checking them manually?  If you can, please post those strings here, using the code snippet.

Also, I can't find any way to tell password_verify() about the parameters used in creating the password_hash() so it may only work with the "vanilla" hash strings.  Might be worth testing that!
0
 
Ray PaseurCommented:
Hmm... No trouble found here.  Are the character sets consistent across PHP and the database?
https://iconoun.com/demo/temp_blacksulfur.php
<?php // demo/temp_blacksulfur.php
/**
 * https://www.experts-exchange.com/questions/28966548/password-verify-issues.html
 *
 * http://php.net/manual/en/function.password-hash.php
 * http://php.net/manual/en/function.password-verify.php
 */
error_reporting(E_ALL);
echo '<pre>';


$pw = 'gooseball';
$h1 = trim(password_hash($pw, PASSWORD_BCRYPT, [12]));
$h2 = password_hash($pw, PASSWORD_DEFAULT);
var_dump($pw, $h1, $h2);

// TEST
if (password_verify($pw, $h1)) echo PHP_EOL . "$pw == $h1";
if (password_verify($pw, $h2)) echo PHP_EOL . "$pw == $h2";

Open in new window

0
 
Black SulfurAuthor Commented:
Still checking this out... But if I run your code in my page I get:

string(9) "gooseball"
string(60) "$2y$10$iSzAQrbKyYoSFLyc8a9ggOQbRjrgC.XGEBFAIbtKnn4cT4aDYHULi"
string(60) "$2y$10$h8ousnvYyyEKEwOYhdtKremY/GkZ/kzGIYbDS5ZGlUAi9UEJXX/Zy"

gooseball == $2y$10$iSzAQrbKyYoSFLyc8a9ggOQbRjrgC.XGEBFAIbtKnn4cT4aDYHULi
gooseball == $2y$10$h8ousnvYyyEKEwOYhdtKremY/GkZ/kzGIYbDS5ZGlUAi9UEJXX/Zy
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Ray PaseurCommented:
Yes, that is what I see, too.  Seems to suggest that password_verify() can recognize either of the hash values.
0
 
Black SulfurAuthor Commented:
Man, I am getting confused now (for a change). Can I do this to test?

$secret = password_verify($password, $db_password);
echo $secret;

Open in new window


That returns a blank screen.

I am not sure where I should put the var_dump in relation to my code.
0
 
Black SulfurAuthor Commented:
Not sure if this helps in any way, but in my DB all the text columns are utf8_general_ci and my integer columns have no collation even though I selected utf8_general_ci. For some reason they just remain empty.
0
 
Black SulfurAuthor Commented:
I tried mine with your example and I just get a blank screen as well.

$password = $link->real_escape_string($_POST['password']);
		$email = $link->real_escape_string($_POST['email']);
		
		$sql = "SELECT password, userID FROM `users` WHERE email = '$email' LIMIT 1";
		$result = $link->query($sql);
		if ($result->num_rows == 1) {
		$row = $result->fetch_assoc();
		$db_password = $row["password"];
			if(password_verify($password, $db_password)) echo PHP_EOL . "$password == $db_password";
			

Open in new window

0
 
Ray PaseurCommented:
The blank screen is because the value in $secret is boolean FALSE.  PHP is not very revealing when you use echo to print information.

A good general design for a login system is given in this article:
https://www.experts-exchange.com/articles/2391/PHP-Client-Registration-Login-Logout-and-Easy-Access-Control.html

You might want to try something like this (untested, but probably close to correct).   It would let you see a password in the form it is stored in the database.
// DO NOTHING TO THIS FIELD -- IT IS NOT USED IN A QUERY
$password = $_POST['password'];

$email = $link->real_escape_string($_POST['email']);

$sql = "SELECT password, userID FROM `users` WHERE email = '$email' LIMIT 1";
$result = $link->query($sql);
if ($result->num_rows == 1) 
{
    $row = $result->fetch_assoc();
    
    // SHOW THE HASH INFORMATION FROM THE DB
    $db_password = $row['db_password'];
    var_dump($db_password);
    
    // SHOW THE HASH OF THE CLIENT INPUT PASSWORD
    $hash = password_hash($password, PASSWORD_BCRYPT, [12]);
    var_dump($hash);
    
    // COMPARE THE HASHED INFORMATION
    if ($db_password == $hash)
    {
        echo PHP_EOL . "MATCH!";
    }
    else
    {
        echo PHP_EOL . "NO MATCH!";
    }
}
else
{
    echo PHP_EOL . "$sql FOUND NOTHING";
}

Open in new window

0
 
Black SulfurAuthor Commented:
Thanks, Ray. I will check that out but I really want to get this to work. I have incorporated your code into mine and it doesn't show a match.

I actually deleted all my data from the database and signed up again using the password "test". Then I tried to login and result is:

string(60) "$2y$10$fwmftAXT/C74/qZrKj488eBbr87Xv9U4fcmX2HfOvgFV1vtTO.PTG"
string(60) "$2y$10$ePzFcO/leSiao2wX8WFrRezgw8wVIXx5Id6FSEOxMWiJQU66EqYt."

I just don't understand why this is. It's driving me crazy!
0
 
Black SulfurAuthor Commented:
Just to double check.. Here is the code above this. Not sure if it might be interfering in any way?

$error = "";

if ($_SERVER['REQUEST_METHOD'] == "POST") {
	
	
	if (!$_POST['email']) {
		
		$error .= "Email required <br>";
	}
	
	if ($_POST['email'] && filter_var($_POST["email"], FILTER_VALIDATE_EMAIL) === false) {

            $error .= "The email address is invalid.<br>";

        }
	
	if (!$_POST['password']) {
		
		$error .= "Password required";
		
	} else {
		
		$password = $_POST['password'];
		$email = $link->real_escape_string($_POST['email']);
		
		$sql = "SELECT password, userID FROM `users` WHERE email = '$email' LIMIT 1";
		$result = $link->query($sql);
		if ($result->num_rows == 1) {
		$row = $result->fetch_assoc();
                //rest of code here

Open in new window

0
 
Black SulfurAuthor Commented:
And one last thing. Here is my insert code for the register page. It might have something to do with it or not. Worth posting though.

$stmt = $link->prepare("INSERT INTO `users` (email, password, firstName, identifier) VALUES (?, ?, ?, ?)");
			$stmt->bind_param("ssss", $email, $password, $name, $identifier);
			$email = htmlentities($_POST['email'], ENT_QUOTES);
			$password = trim(password_hash($password, PASSWORD_BCRYPT, [12]));
			$name = htmlspecialchars($_POST['name']);
			$identifier = bin2hex($identifier);
			$stmt->execute();
			$stmt->close();

Open in new window

0
 
Black SulfurAuthor Commented:
I figured it out!!!!!!

It was the one line in my register page code.

I changed this:

$password = trim(password_hash($password, PASSWORD_BCRYPT, [12]));

Open in new window


to this:

$password = trim(password_hash($_POST['password'], PASSWORD_BCRYPT, [12]));

Open in new window


Man, Oh man was that painful. Can I give myself points?? :P
0
 
Ray PaseurCommented:
OK, it looks like string comparison is inadequate for dealing with these hashed passwords; the same password will not always hash into the same output string.  We must use the related PHP functions to compare the values.  Try these three links:
https://iconoun.com/demo/temp_blacksulfur.php?q=secret <-- This one works.
https://iconoun.com/demo/temp_blacksulfur.php?q=foo
https://iconoun.com/demo/temp_blacksulfur.php

Here is the test script.
<?php // demo/temp_blacksulfur.php
/**
 * https://www.experts-exchange.com/questions/28966548/password-verify-issues.html
 *
 * READ THE USER-CONTRIBUTED NOTES CAREFULLY!
 * http://php.net/manual/en/function.password-hash.php
 * http://php.net/manual/en/function.password-verify.php
 *
 * References for PHP and MySQL(i):
 *
 * http://php.net/manual/en/mysqli.overview.php
 * http://php.net/manual/en/class.mysqli.php
 * http://php.net/manual/en/class.mysqli-stmt.php
 * http://php.net/manual/en/class.mysqli-result.php
 * http://php.net/manual/en/class.mysqli-warning.php
 * http://php.net/manual/en/class.mysqli-sql-exception.php <-- DID NOT WORK PHP 5.3+, MySQL 5.1+
 *
 * http://php.net/manual/en/mysqli.construct.php
 * http://php.net/manual/en/mysqli.real-escape-string.php
 * http://php.net/manual/en/mysqli.query.php
 * http://php.net/manual/en/mysqli.errno.php
 * http://php.net/manual/en/mysqli.error.php
 * http://php.net/manual/en/mysqli.insert-id.php
 *
 * http://php.net/manual/en/mysqli-result.num-rows.php
 * http://php.net/manual/en/mysqli-result.fetch-array.php <-- DO NOT USE THIS
 * http://php.net/manual/en/mysqli-result.fetch-object.php
 */
ini_set('display_errors', TRUE);
error_reporting(E_ALL);
echo '<pre>';


// TEST AGAINST THIS PASSWORD
$vwd = 'secret';


// DATABASE CONNECTION AND SELECTION VARIABLES - GET THESE FROM YOUR HOSTING COMPANY
$db_host = "localhost"; // PROBABLY THIS IS OK
$db_name = "??";
$db_user = "??";
$db_word = "??";
require_once('RAY_live_data.php');
// OPEN A CONNECTION TO THE DATA BASE SERVER AND SELECT THE DB
$mysqli = new mysqli($db_host, $db_user, $db_word, $db_name);

// DID THE CONNECT/SELECT WORK OR FAIL?
if ($mysqli->connect_errno)
{
    $err
    = "CONNECT FAIL: "
    . $mysqli->connect_errno
    . ' '
    . $mysqli->connect_error
    ;
    trigger_error($err, E_USER_ERROR);
}

// ACTIVATE THIS TO SHOW WHAT THE DB CONNECTION OBJECT LOOKS LIKE
// var_dump($mysqli);


// CREATING A TABLE FOR OUR TEST DATA
$sql
=
"
CREATE TEMPORARY TABLE my_table
( id    INT          NOT NULL AUTO_INCREMENT PRIMARY KEY
, pwd   VARCHAR(255) NOT NULL DEFAULT ''
, xwhen TIMESTAMP    NOT NULL
)
"
;

// IF mysqli::query() RETURNS FALSE, LOG AND SHOW THE ERROR
if (!$res = $mysqli->query($sql))
{
    $err
    = 'QUERY FAILURE:'
    . ' ERRNO: '
    . $mysqli->errno
    . ' ERROR: '
    . $mysqli->error
    . ' QUERY: '
    . $sql
    ;
    trigger_error($err, E_USER_ERROR);
}

// ACTIVATE THIS TO SHOW THE RESULTS OF THE QUERY
// var_dump($res);


// LOADING OUR VERIFICATION DATA INTO THE TABLE
$pwd = password_hash($vwd, PASSWORD_DEFAULT);
$pwd = $mysqli->real_escape_string($pwd);
$sql = "INSERT INTO my_table ( pwd ) VALUES ( '$pwd' )";
$res = $mysqli->query($sql);
if (!$res)
{
    $err
    = 'QUERY FAILURE:'
    . ' ERRNO: '
    . $mysqli->errno
    . ' ERROR: '
    . $mysqli->error
    . ' QUERY: '
    . $sql
    ;
    trigger_error($err, E_USER_ERROR);
}

// ACTIVATE THIS TO SHOW THE QUERY
// echo PHP_EOL . $sql;


// INTERPRET THE URL ARGUMENT AND TRY THE QUERY
$arg = !empty($_GET['q']) ? $_GET['q'] : 'Missing "q=" URL parameter';

$sql = "SELECT id, pwd FROM my_table WHERE id=1 LIMIT 1";
$res = $mysqli->query($sql);
$num = $res->num_rows;
if ($num)
{
    $row = $res->fetch_object();
    if (password_verify($arg, $row->pwd))
    {
        echo PHP_EOL . "Found PW match for <b>$arg</b> in row with id=$row->id";
    }
    else
    {
        echo PHP_EOL . "Found no PW match for <b>$arg</b>";
    }
}

Open in new window

HTH, ~Ray
0
 
Ray PaseurCommented:
Regarding this:
https://www.experts-exchange.com/questions/28966548/password-verify-issues.html#a41777011

I thought you already had assigned $password with this:
$password = $_POST['password'];

But if your script had not made that assignment, you would have gotten a Notice when your script tried to use an undefined variable.

Check AntiPractice #4 here to learn how to visualize undefined variables!
https://www.experts-exchange.com/articles/12293/AntiPHPatterns-and-AntiPHPractices.html

Seriously, you might want to have a look at this article, too.  It contains tested and working code samples you can copy and install right now.
https://www.experts-exchange.com/articles/2391/PHP-Client-Registration-Login-Logout-and-Easy-Access-Control.html

Then once you have that much working, you can go back in and do things like refactor the md5() into hashed passwords instead.
0
 
Black SulfurAuthor Commented:
Thanks, Ray. Yes, I checked out your link to a full solution for client registration, login and logout ( I do intend to use this in future)  which I could just copy and paste but I am trying to do it from scratch on my own to try help me learn and understand better. Unfortunately I get stuck ( a lot) but at least I learn something when I get stuck and really helpful people like you come along and help me out! :)

It would seem I have another problem now which I will ask in a related question.
0

Featured Post

Become an Android App Developer

Ready to kick start your career in 2018? Learn how to build an Android app in January’s Course of the Month and open the door to new opportunities.

  • 9
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now