Strange problem with the length of the field gotten from database [duplicate] - php

This question already has answers here:
Why is password_verify returning false?
(2 answers)
Closed 2 years ago.
I am using php 5.4 with this backwards compatibility script: https://github.com/ircmaxell/password_compat/blob/master/lib/password.php
that shouldn't matter though, because I can get the hashing and verification process working in my registration function:
$hash = password_hash($pass, PASSWORD_DEFAULT);
echo $pass;
echo $hash;
if( password_verify($pass,$hash) )
echo 'success';
else echo 'failure';
//success is always shown
//EXAMPLE INPUT
$pass = 'password';
//EXAMPLE OUTPUT
password$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYSsuccess
but whenever I try to store the hash in a MySQL database and then retrieve it for the verify function, it always fails. Here is my login function:
function user_login( $mysqli, $email, $pass ){
$err_msg = 'login: '.$mysqli->error.' | '.$email;
if( $stmt = $mysqli->prepare('SELECT password FROM users WHERE email=?') ) :
if( !$stmt->bind_param('s', $email) ) log_sql_error( $err_msg );
if( !$stmt->execute() ) log_sql_error( $err_msg );
if( !$stmt->bind_result( $hash ) ) log_sql_error( $err_msg );
if( $stmt->fetch() === FALSE ) log_sql_error( $err_msg );
if( !$stmt->close() ) log_sql_error( $err_msg );
//I can see that these values are identical to the ones
//echoed out in the registration function
echo $pass;
echo $hash;
if( password_verify($pass,$hash) )
echo 'success';
else echo 'failure';
else : log_sql_error( $err_msg );
endif;
}
//failure is always shown
//EXAMPLE INPUT
$pass = 'password';
//EXAMPLE OUTPUT
password$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYSfailure
My 'password' column has this datatype: VARCHAR(255) NOT NULL
No php errors show up so the only thing I can think of is that the hash value is not formatted in the same way when it comes out of the database as when it went in, but when I echo out the values, they appear to be identical.
How else can I debug this / what is wrong with my code?
Thanks
UPDATE:
This definitely has something to do with encoding:
$hardcode_hash = '$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS';
echo $hash;
echo '<br/>';
echo $hardcode_hash;
echo '<br/>';
if( $hash == $hardcode_hash )
echo 'success';
else echo 'failure';
//OUTPUT
$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS
$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS
failure
how do I reformat the SQL value to match the output of password_hash? Here's what I've tried:
(string)$hash
utf8_encode($hash)
if I do:
$hash = settype($hash,"string");
if($hash == $hardcode_hash) returns true, but password_verify($pass, $hash) still returns false

Found the problem. when I did this:
echo strlen($hash)
it printed 90, which is strange because there were definitely no spaces at the end when I printed out the success/failure message, and the field has a varchar length of 255
I added this line:
$hash = substr( $hash, 0, 60 );
And now it works fine.
Its strange that no one else seems to have run into this issue. There are similar posts about password_verify, but none of them required this type of conversion, or any conversion for that matter:
php password_verify not working
password_verify php not match
http://forums.phpfreaks.com/topic/283407-need-help-with-password-verify/
Using PHP 5.5's password_hash and password_verify function
One thing that bothers me is this prevents the code from being forward compatible. How will I know that the hash is 60 characters long when the default changes?

I was having the same issue with password_verify(). For me i had declared my username and password as VARCHAR(50). Therefore it was not inserting the hash value in my database which is obviously more than 50 characters. Therefore every time I used password_verify() I got a false. I changed my database values to varchar(255). Inserted data again, tested and it works.

Just for future reference. I had the same issue with passwords failing for no reason. When I took a closer look at it I saw that the password field in the database was not big enough to store the full hash so some characters were cut off. After increasing the size of the database field it worked perfectly.

I had the same issue you had with it not working, for some reason it seems to help putting the:
$hash = substr( $hash, 0, 60 );
into the code although my string was already 60 characters long.

I had the same issue and it was still not working despite ensuring my database columns were varchar(255), that the hashes were 60 characters, and ensuring my encoding was UTF-8 all the way through. I'm pretty new to PHP and SQL so I won't pretend to understand exactly why it worked, but I managed to fix it so I hope this post will help other folks with the same problem.
It turned out that the underlying reason password_verify() wasn't verifying my hashes was because I had made a prepared statement that used a stored procedure earlier in the script without fetching all the results from the query properly to clear the buffer, before closing and reopening the connection to perform the next query. Calling next_result() on the mysqli_link after closing the statement will make sure any results are consumed.
Additionally, I was then using another prepared statement with a stored procedure to make the insert for the password, but I still needed to make calls to store_result() and free_result() even though no result sets were returned from the insert. I'm assuming the combination of these things was corrupting my data somewhere along the line, resulting in password_verify() returning false on seemingly identical hashes.
This answer was for a different problem but I found it useful for learning how to properly close out prepared statements with stored procedures.

Related

Mysqli prepared statement stmt_num_rows returns 0

For some reason stmt_num_rows always ends up being 0. No matter if I execute the query with the correct email and word or the wrong one.
This is the code:
include_once './Connect.php';
$db = new DB_Connect();
$con = $db->connect();
$password = $_POST["Password"];
$email = $_POST["Email"];
$word = $_POST["Word"];
$true = 'true';
$false = 'false';
$response = array();
$selectquery = mysqli_prepare($con, "SELECT ID FROM users WHERE Email = ? AND Word = ?");
mysqli_stmt_bind_param($selectquery , "ss" , $email , $word);
mysqli_stmt_execute($selectquery);
mysqli_stmt_store_result($selectquery);
mysqli_stmt_bind_result($selectquery, $ID);
if (mysqli_stmt_num_rows($selectquery) > 0){
$response[resp] = $true;
$updatequery = mysqli_prepare($con , "UPDATE users SET Password = ? WHERE Email = ? AND Word = ?");
mysqli_stmt_bind_param($updatequery ,"sss", $password, $email, $word);
mysqli_stmt_execute($updatequery);
mysqli_stmt_close($updatequery);
}else{
$response[resp] = $false;
}
echo json_encode($response);
mysqli_stmt_close($selectquery);
mysqli_close($con);
Run down of the code: Password, Email and Word are posted from android. First there is a query to check if there is a user (row) in the table with the corresponding Email and Word. If that is true the ID is added. Then stmt_num_rows is called to check the number of rows fetched, yet the number of rows that is fetched ends up being 0 (I get a response as "false"). But if it was one then the UPDATE query would be called and I would receive a response "true". Does anyone know the mistake I've made?
Thank you!
Putting our comments to an answer to close this with:
Mine:
"Try removing / commenting those out and try it again. If that fails, then your POSTs may be failing. Check for errors against those and variables, and in your query."
and:
"also make sure that no whitespace is being introduced, if so, trim() and do a var_dump. Remember that POST arrays are case-sensitive. Password and password etc. are two different animals. Same goes for the other POST arrays"
Ivan's:
"Fred you were right the issue wasn't in the php it was actually the data posted. Since I'm using the Async Http library i forgot to post the actual parameters I want to send. I set the params to null"
Passwords
I noticed that you may be storing passwords in plain text. This is not recommended.
Use one of the following:
CRYPT_BLOWFISH
crypt()
bcrypt()
scrypt()
On OPENWALL
PBKDF2
PBKDF2 on PHP.net
PHP 5.5's password_hash() function.
Compatibility pack (if PHP < 5.5) https://github.com/ircmaxell/password_compat/
Other links:
PBKDF2 For PHP
Important sidenote about column length:
If and when you do decide to use password_hash() or crypt, it is important to note that if your present password column's length is anything lower than 60, it will need to be changed to that (or higher). The manual suggests a length of 255.
You will need to ALTER your column's length and start over with a new hash in order for it to take effect. Otherwise, MySQL will fail silently.

Why is mysqli num rows not returning anything?

I have some code which is supposed to verify the username and password for a login (Don't yell at me, I already sanitize the strings earlier in the code using GUMP):
$verif_query="SELECT * FROM users WHERE username = \"".$_POST['user']."\" AND password = \"".hash("sha512",$_POST['passwd'].mysqli_fetch_assoc(mysqli_query($DB,"SELECT salt FROM users WHERE username = \"".$_POST['user']."\"")))."\"";
$userpass_verif = mysqli_query($DB,$verif_query);
if(mysqli_num_rows($userpass_verif) <= 0){
die("Invalid un/pass");
}
UPDATE: I forgot to mention, I echoed out $verif_query and ran it against phpmyadmin, and it returned 1 row. Sorry, my question was not comprehensive.
UPDATE2: I messed the code example up while typing the question. I did verify the DB connection and I did include the $DB in the query. Again, sorry for the bad question.
When you do:
mysqli_fetch_assoc(
mysqli_query(
"SELECT salt FROM users WHERE "
. "username = \"" . $_POST['user'] . "\""
)
)
You are actually getting an associative array, not the user's salt as a string. If the user's salt was 'the-salt', this is what you will get:
Array
(
[salt] => the-salt
)
When concatenating the users password (e.g. 'the-password') and that array, you will get:
the-passwordArray
As the password hash used for verification will be made out of that string, the query will (most probably) not match anything and you won't get any rows returned from the verification query.
use this before die() and tell us the error you got
echo mysqli_errno($this->db_link);

How to save a hash of a password in MySQL

I have the following table in my database called db_pass:
id | pass
=================
1 | dalmation123
I understand that I cannot store any password in plain text format in my database, how do I go about setting up a hash? This is the code I am using below. I would appreciate some help on how to change my table db_pass as well.
if(isset($_POST['pmsubmit']))
{
LoginSubmit('pm', 'pmname', 'pmpass');
}
if(isset($_POST['tssubmit']))
{
LoginSubmit('ts', 'dept', 'tspass');
}
function LoginSubmit($pm_or_ts, $the_name_input, $the_pass_input)
{
global $pdo;
$posted_name = $_POST[$the_name_input];
$posted_pass = $_POST[$the_pass_input];
// check if password matches the one in the table
$query = $pdo->prepare("SELECT * FROM db_pass WHERE pass = :pass");
$query->execute(array(":pass" => $posted_pass));
// if there is a match then we log in the user
if ($query->rowCount() > 0)
{
// session stuff
$_SESSION[$the_name] = $posted_name;
// refresh page
header( 'Location: ' . $pm_or_ts . '/index.php' ) ;
exit;
}
// if there is no match then we present the user with an error
else
{
echo "error";
exit;
}
}
$query = $pdo->prepare("SELECT * FROM db_pass WHERE pass = :pass");
$query->execute(array(":pass" => crypt($posted_pass)));
Don't ask me which algorithm crypt actually uses. The manual entry is totally nonsensical - apparently just checking the value of a constant changes the algorithm used by crypt() which is ridiculous ....
And it's alright people saying bcrypt. But bcrypt isn't a core PHP function. If they mean write your own, then it's a stupid idea - because your implementation would undoubtedly have flaws. If they mean a library they need to point one out - PHPass is commonly recommended, but I have no knowledge to recommend it myself.
It's hardly surprising most people still use sha1 is it?
It all comes down to this. you need to perform an operation on the user password before you save it to the database. you then perform the same operation on the submitted password before checking the if that password is valid for the username/password combination.
in most cases the "operation" is a hashing or encryption process such as MD5 or bcrypt
In MySQL you could use the BINARY type to actually store hashes. A simple hash table in MySQL could look like:
CREATE TABLE IF NOT EXISTS `hastable` (
`hash` binary(20) NOT NULL,
`value` blob NOT NULL,
PRIMARY KEY (`hash`)
);
For example a SHA1 hash is always 160 bits/20 bytes long and could be stored such a binary column. Using PHP, you could get the hash as follows: hash( 'sha1', $key, true );
But that has nothing to do with storing passwords…

What am I doing wrong with this crypt()-based bcrypt authentication?

I've cribbed this code almost verbatim from a bunch of very helpful answers here on SO, so I can't get my head around what's wrong.
First, here's my function for creating a user account:
function BFcrypt($password,$cost)
{
$chars='./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$salt=sprintf('$2a$%02d$',$cost);
for($i=0;$i<22;$i++) $salt.=$chars[rand(0,63)];
return array(
'salt'=>$salt,
'hash'=>crypt($password,$salt)
);
}
Then, when a user goes to login:
case 'login':
$login =$_POST['login'];
$pwd =$_POST['pwd'];
$sql ="SELECT * FROM `users` WHERE `users`.`login`='$login' LIMIT 1;";
if($query = mysql_query($sql)){
$row=mysql_fetch_assoc($query);
print_r($_POST);
print_r($row);
$hash = $row['password'];
if(crypt($pwd,$hash)==$hash){
echo"SUCCESS";
}else{
echo"FAILURE";
}
}
The login function appears to always be failing. I've set it to show me $pwd, $hash and crypt($pwd,$hash), and for some reason, crypt($pwd,$hash) never seems to == $hash.
Here's a row in the database for a sample user (I'm logging the salt now, though I know it's supposed to be included in the hash:
'id'=>'680',
'login'=>'argh',
'password'=>'$2a$10$BWZAX7wrwQp5iyK4kh6VLunqy82eiXg7GaDs6mJLqdgT5s2qiUqYW',
'salt'=>'$2a$10$BWZAX7wrwQp5iyK4kh6VL5',
'first'=>'argh',
'last'=>'argh',
'zip'=>'00000',
'email'=>'argh',
'date updated'=>'2012-12-12 16:05:29'
I believe that when I call crypt($pwd,$hash),it truncates $hash, leaving only the original 22-character salt (plus prefix), thus the output will be the same as $hash as long as $pwd is the same. I'm seeing clearly there's an issue here in that the salt I'm recording is one character longer than the one that ends up appended to the hash, but it's the appropriate length for blowfish, and anyway, making it one character shorter doesn't seem to help.
I can't figure out what I'm doing wrong here. Any help would be appreciated.
Based on your own salt value and password of 'argh' I ran a small test script:
$hash = crypt('argh', '$2a$10$BWZAX7wrwQp5iyK4kh6VL5');
// $2a$10$BWZAX7wrwQp5iyK4kh6VLuIzJHihvZTdfpRXNkTPVKkTiGfLDl1RO
var_dump(crypt('argh', $hash) == $hash);
// bool(true)
The problem doesn't seem to be in the code you've shown.
You could check your database field width to store the password hash, which should be at least 60 wide. And while you're at it, fix your SQL injection vulnerability (by using prepared statements most preferably).

Error comparing hash to hashed mysql password (output values are equal)

Im trying to compare a hashed password value in a mysql database with the hashed value of an inputted password from a login form.
However, when I compare the two values it says they aren't equal. I removed the salt to simply, and then tested what the outputs were and got the same values
$password1 = $_POST['password'];
$hash = hash('sha256', $password1);
...connect to database, etc...
$query = "SELECT *
FROM users
WHERE username = '$username1'";
$result = mysql_query($query);
$userData = mysql_fetch_array($result);
if($hash != $userData['password']) //incorrect password
{
echo $hash."|".$userData['password'];
die();
}
...other code...
Sample output:
7816ee6a140526f02289471d87a7c4f9602d55c38303a0ba62dcd747a1f50361| 7816ee6a140526f02289471d87a7c4f9602d55c38303a0ba62dcd747a1f50361
Any thoughts?
I was having the exact same problem. var_dump() was telling me that I had two variables with the same properties, string(128). The only way I was able to get the comparison to work was to cast the hashed values as strings:
$password1 = $_POST['password'];
$hash = (string)hash('sha256', $password1);
...
$userData = (string)mysql_fetch_array($result);
if($hash == $userData) {
//This should return true.
}
Try using strcmp. String comparisons with == or != rarely go well.
if(strcmp($hash, $userData['password']) != 0) {
//this would be where the password was incorrect.
}
It may very well be treating it as a number for some reason and failing the comparison.
Try switching != to == and switch content. Like this
if($hash == $userData['password']) //incorrect password
{
//proc login...
}
else
{
echo $hash."|".$userData['password'];
die();
}
I'm not sure why is that happening but you can be sure it will work in my case
EDIT: you did something wrong in your case. works for me
== is an object hashcode comparison, you need to use a strcmp function to compare string literals.
Not sure if you ever got this solved but I just wasted 30 minutes with the exact same problem. Turns out my mysql value had an extra space at the end. It was a test user I manually added to the database and somehow got an extra space when copying and pasting the hashed password.
Not sure if this applies to your situation or not but I thought I'd share anyway.

Categories