Solved

password_verify issues

Posted on 2016-08-30
15
36 Views
Last Modified: 2016-08-30
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
Comment
Question by:Black Sulfur
  • 9
  • 6
15 Comments
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41776549
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
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41776581
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
 

Author Comment

by:Black Sulfur
ID: 41776727
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
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41776738
Yes, that is what I see, too.  Seems to suggest that password_verify() can recognize either of the hash values.
0
 

Author Comment

by:Black Sulfur
ID: 41776757
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
 

Author Comment

by:Black Sulfur
ID: 41776764
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
 

Author Comment

by:Black Sulfur
ID: 41776768
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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 108

Accepted Solution

by:
Ray Paseur earned 500 total points
ID: 41776793
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
 

Author Comment

by:Black Sulfur
ID: 41776886
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
 

Author Comment

by:Black Sulfur
ID: 41776914
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
 

Author Comment

by:Black Sulfur
ID: 41776933
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
 

Author Comment

by:Black Sulfur
ID: 41777011
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
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41777091
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
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41777094
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
 

Author Comment

by:Black Sulfur
ID: 41777114
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

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Part of the Global Positioning System A geocode (https://developers.google.com/maps/documentation/geocoding/) is the major subset of a GPS coordinate (http://en.wikipedia.org/wiki/Global_Positioning_System), the other parts being the altitude and t…
These days socially coordinated efforts have turned into a critical requirement for enterprises.
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
The viewer will learn how to count occurrences of each item in an array.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now