Why does password_verify return false?
There are a variety of reasons why password_verify
could be returning false, it can range from the setup of your table to the actual comparing of the password, below are the common causes of it failing.
Column Setup
The length of the password column in your table is too short:
- If you are using
PASSWORD_DEFAULT
then it is recommended to store the result in a database column that can expand beyond 60 characters (255 characters would be a good choice). - If you are using
PASSWORD_BCRYPT
then it is recommended to store the result in a database column that is 60 characters becausePASSWORD_BCRYPT
will always result in a 60 character string or FALSE on failure.
- If you are using
Password Sanitization
Another common cause is when developers try to "clean" the user's password to prevent it from being malicious, as a result, this causes the input to be different to what is being stored in the table. It is not even necessary to escape the input, you should use prepared statements instead. You shouldn't even trim
the passwords as that could change that which was originally provided.
Password Verification
When using password_verify
you need to compare the plaintext password with the hash from the database/file/some-other-storage-method, not compare hashes (the implication here being that you need to have stored the hashed password of the user when they register):
<?php
$hashed = password_hash('test', PASSWORD_DEFAULT);
$password = 'test';
if (password_verify($password, $hashed)) {
echo 'success';
} else {
echo 'fail';
}
?>
Ensure that you are actually passing a hash to password_verify
and not something else by dumping it.
Repl
Hardcoded Passwords
In the instance that you are using a hardcoded hash and you are facing issues, ensure that you are using single quotes instead of double quotes when storing the value in the variable as the $
will be interpreted in when using double quotes:
<?php
// Undefined variable: QHpfI0MfQWjvsVQWRdFHSOX6WqG8LSf0iFGiKs0Fz0RvqhpFOpAKu :1
$incorrect = "$2y$10$QHpfI0MfQWjvsVQWRdFHSOX6WqG8LSf0iFGiKs0Fz0RvqhpFOpAKu";
$correct = '$2y$10$QHpfI0MfQWjvsVQWRdFHSOX6WqG8LSf0iFGiKs0Fz0RvqhpFOpAKu';
?>
Repl - Comment out respectively.
Troubleshooting
var_dump()
the hashed password on registration right before you insert it into your database, and var_dump()
it again after you fetch it from your database when you are about to password_verify()
it. Ensure both hashes are identical. If they are, and the plaintext passwords are identical too, there's no reason for password_verify
to fail. It only fails if the hash gets modified in some way on its roundtrip through the database, or if the plaintext passwords aren't identical.
Ensure that you are passing a correct algorithm to password_hash
has the second parameter.
Addendum
As per the documentation:
Caution It is strongly recommended that you do not generate your own salt for this function. It will create a secure salt automatically for you if you do not specify one.
As noted above, providing the salt option in PHP 7.0 will generate a deprecation warning. Support for providing a salt manually may be removed in a future PHP release.
PHP password_verify always returning false even when hardcoded
I could not find any problem in your code here but since hashing and verifying is a process which depends on a lot of factors to be successful i would like to give you some tips so that you can check it yourself for any potential problems.
make sure you are not escaping/sanityzing the password before
hashing it. This way you're altering the stored password. Let$password = $_POST['password'];
both when you create the account and
when you check if the password match at login.
make sure you are enclosing the hash variable in single quotes (') and not double quotes (").using double quotes makes PHP read each paired character with "$" as indivisual variables which will probably cause your code to break, USE SINGLE QUOTES INSTEAD.
Ensure the Password field in the database (that stores the hashed
password) is able to store up to 255 characters. From the documentation
it is recommended to store the result in a database column that can
expand beyond 60 characters (255 characters would be a good choice). If the field is narrower the hash will be truncated and you'll never
have a match.As you get the user by username at login ensure that username is unique
as long as it is your primary key (in the table
definition). Good idea to check this also upon user registration and login (at php level).echo both hash and entered
values and make sure they match the ones that were inserted and
generated during password_hash() if the database value was different
(the hash), make sure the type of its column is varchar(256), the
hash is usually 60 characters long but the hashing function is
frequently improved so that length may expand in the future.if the entered value was different (the user password), make sure the
filtering isn't corrupting the password value.also check if another variable has the same name as the one you're storing the password in.
If
password_verify($password, password_hash($password, PASSWORD_DEFAULT))
"works", then the problem is that $row['Password'] does not contain what is expected - including not being generated correctly.If it "doesn't work" then
another line is causing the observed behavior. Both of these
outcomes allow focusing on a refined problem set.try changing the password from the another column that matched and copy it to your password column and enter that password to check.if it worked then there is problem with your stored password
try copying this hash to your password column
$2y$10$uDnEpQpkh9RO5tWwOrHtneLAuYMRDstRaKGZFyHubObDR0789OMO6
this is the hashed password for 123456 using bycrypt. select this password and try to verify it with password_verify(123456,$yourhashedfromdatabase) after selecting this from sql if it works then there is probably some manipulation after your data is entered and goes to the database. it it does not then check if the password that reaches the database is exactly as your typed by echoing it.
UPDATE: after you updated your code i see that while entering the password you use "Pass" column but while extracting you use "Password" column. this could be the issue
password_verify not returning true/false
After testing your entire code, I have come to the following conclusion.
The problem here is that you are escaping the password while inserting it into your database, which is something I did raise in comments from the beginning.
"side note: you shouldn't escape a password/hash function, passwords such as
123'\abc<
are perfectly valid and will be modified on insertion."
$password = mysqli_real_escape_string($conn, $username);
Side note for ^ - Consult Edit #2 below, near "However...":
Simply don't use it, just keep/use the assignment normally.
Both password_hash()
and password_verify()
do their job, so there's no need to escape passwords.
You will need to remove it from the code that you used to insert it into the database with, and start over again with a new set of hashes.
That escaping function is most likely adding a character during insertion.
Side note: Just for the record, my password column is VARCHAR
, yet that shoulnd't be a difference from your CHAR
(Edit: consult footnote). If it is then ALTER your column to be VARCHAR
.
The manual on password_hash()
though, suggests using 255 for a length, being a good bet.
- http://php.net/manual/en/function.password-hash.php
Edit footnote:
As per a comment I posted beneath my answer.
It looks to have a difference. This Q&A What's the difference between VARCHAR and CHAR? shows it, as per the accepted answer
VARCHAR is variable-length.
CHAR is fixed length.
- https://stackoverflow.com/a/1885635/1415724
Edit #2:
After further testing to see if it made a difference by ALTER'ing the password column from VARCHAR(255)
to CHAR(60)
made a difference; it did not.
Tests performed:
- Inserted a new hash without the escaping function and verifying:
TRUE
. - Inserted a new hash with the escaping function and verifying:
FALSE
.
Therefore and as I stated originally; the fault lies with the use of mysqli_real_escape_string()
.
However and going over your code again, this line:
$password = mysqli_real_escape_string($conn, $username);
You were using the $username
variable here which also accounts for the wrong value being inserted in the database. All of these put together were the problems from the get go.
Why is password_verify returning false?
Probably the problem is with your column length, from the manual:
it is recommended to store the result in a database column that can expand beyond 60 characters (255 characters would be a good choice). link
PHP password_verify returning false
You overwrite your $password
when you include your dbconnection.
include('connection.php');
has:
$password="mypassword";
Previously you set:
$password=validateFormData($_POST['password']);
so your hashed password is not the user's password, but your DB password.
I would prefix all DB credentials variables with db_
. So your database password variable would then be $db_password
. This will allow you to have distinct variables throughout your project (I'd think).
Additionally you should be using $formPass
, not $newpass
. The $newpass
is going to be double hashed at the verify
function.
$formEmail=validateFormData($_POST['loginEmail']);
$formPass=validateFormData($_POST['loginPassword']);
$newPass=password_hash($formPass,PASSWORD_DEFAULT);
so change:
if(password_verify($newPass,$LogPass))
to:
if(password_verify($formPass, $LogPass))
password_verify() returning false when passwords match
password_verify() works with the function password_hash();
change:
$hash = hash('sha512', $password);
to:
$hash = password_hash($password, PASSWORD_DEFAULT);
Related Topics
How to Check If an Integer Is Within a Range
Uncaught Reflectionexception: Class Log Does Not Exist Laravel 5.2
How to Generate Unique Id in MySQL
How Add Class='Active' to HTML Menu with PHP
PHP Warning: Module Already Loaded in Unknown on Line 0
How to Use Regexiterator in PHP
How to Change/Custom Password Field Name for Laravel 4 and Laravel 5 User Authentication
How to Setup Table Prefix in Symfony2
How to Display a Date as Iso 8601 Format with PHP
PHP Curl: I Need a Simple Post Request and Retrival of Page Example
How to Delete a Folder with Contents Using PHP
Hiding True Database Object Id in Url'S
In PHP, Can You Instantiate an Object and Call a Method on the Same Line
Fix Malformed Xml in PHP Before Processing Using Domdocument Functions