Basically, I've just started working with PHP, and am trying to get to grips with the password_hash function. When a user registers I hash their password using:
$hashed_password = password_hash($p, PASSWORD_DEFAULT);
Then, that hashed password is stored in my database. I then want to retrieve the password for login. So my code is written so that once the form is submitted, the email and password strings are sanitized, it the checks that they're not blank, once that's done, I take the user entered password, and hash it using:
$hash = password_hash($password, PASSWORD_DEFAULT);
Once again. Once this has done I connect to my DB, and try to select the user using:
$q = "SELECT * FROM users
WHERE email='$email' AND password='$hash'";
However. When debugging I've noticed that the user entered string, despite being the same as the string entered when signing up is different when hashed. so I've been echo'ing $hash and getting:
$2y$10$LQ55Q1DUqIgRx/2hgnbrnuQrYvrrBrq4WEFmV8TuxII6rDocaWzt2
but the exact same string "password" is stored in the db as:
$2y$10$omNPA7cviUm.6asuhJIJ8Or.m9WeHhJMkCqYYijel5g.NflbdVnV.
How do I get it so that when the user enters their password, it hashes the string and matches the one in the DB, so that they can log in? Am I missing something
Cheers
You'd need something like this:
$hashed_password = mysql_result(mysql_query("SELECT password FROM users WHERE email='$email'"));
$match = password_verify( $password, $hashed_password );
if($match){
echo 'Password is valid';
} else {
echo 'Password is not valid' ;
}
Related
I created registration form with hashed password and now I am not really sure how to fetch the hashed password and be able to login.
Registration.php
$hash = password_hash($password, PASSWORD_BCRYPT);
$insert = $con->query("INSERT INTO Client (firstName, lastName, email, password, keyVerification) VALUES
('$firstName', '$lastName', '$email', '$hash', '$keyVerification')");
Login.php
$email = $con->real_escape_string($_POST['email']);
$password = $con->real_escape_string($_POST['password']);
$hash = password_hash($password, PASSWORD_BCRYPT);
$result = $con->query("SELECT * FROM Client WHERE email = '$email' AND password = '$hash' LIMIT 1");
Unfortunately this way doesn't work when I want to login with registered email and password - I am just getting error I set up of incorrect password or email. I believe I am making the mistake with hashed password. Where my logic failed ?
You get a new seed whenever you call password_hash so you can't compare the output of it with the previous output, even when the input is the same.
Search the database to find the hashed password for the email address given.
Then compare the submitted password to the known hash using password_verify.
if (password_verify($_POST['password'], $hash_from_database)) {
Asides:
$password = $con->real_escape_string($_POST['password']);
$hash = password_hash($password, PASSWORD_BCRYPT);
Don't escape the password to make it suitable for inserting into SQL and then hash the escaped password.
Escape what you want to put into the database, which is the hashed password.
… but don't use real_escape_string in the first place. Use placeholders.
You should try with the password_verify ( string $password , string $hash ) : bool function, as the hash function will generate new hashes for the same password string each time.
Read more here: https://www.php.net/manual/en/function.password-verify.php
User registration works fine. After registration, this login page is opened and the message comes up that password, username and hash are undefined variables on my select line and when I echo the hash.
When trying to login "Invalid login credentials" error pops up, but also "Password is valid", and the hash is printed as well.
if (isset($_POST['username']) and isset($_POST['password'])){
// Assigning posted values to variables.
$username = cleanData($_POST['username']);
$password = cleanData($_POST['password']);
$hash = password_hash($password, PASSWORD_DEFAULT);
$verify = password_verify($password, $hash);
if(password_verify($password, $hash)) {
echo 'Password is valid!';
} else {
echo 'Invalid password.';
}
}
// Checking if the values exist in the database or not
$query = "SELECT * FROM `user` WHERE (username='$username') AND (password='$password')";
echo $hash;
$result = mysqli_query($connection, $query) or die(mysqli_error($connection));
$count = mysqli_num_rows($result);
// If the posted values are equal to the database values, then session
is created for the user.
if ($count == 1){
$_SESSION["loggedIn"] = true;
$_SESSION['username'] = $username;
}else{
// error for not matching credentials
$fmsg = "Invalid Login Credentials.";
I suspect that I have done something horribly wrong with the placement and requirements of my SELECT statement , but it still does not explain why these variables are coming up as undefined. Perhaps I can move the SELECT statement to replace the "password is valid" message and go from there?
CleanData is a function to sanitise input.
So, the issue is you're kind of doing this:
if (username and password are set) {
username = xxx
password = xxx
hash password
verify password
display results
}
do sql query based on username and password
So, you've got code outside of your original IF trying to utilize variables that might not have been created.
Your SQL query and all code after that will be called even if you did not pass username and password to the php page.
You might be better off doing something like this at the beginning of your script:
if (username and password are not both set in post vars)
display error
exit
}
username = xxx
password = xxx
Then you can be sure that those vars definitely are defined without having to check over and over in the page.
Also, the pseudocode is on purpose. Trying to get my message across in layman's terms :)
With this code, you will always receive the "password is valid" message, because you are verifying the password that the user entered against the hash that you just generated from that same password!
<!-- Incorrect code: This always determines the password is valid! -->
$hash = password_hash($password, PASSWORD_DEFAULT);
if (password_verify($password, $hash)) {
echo 'Password is valid!';
}
You are supposed to use password_hash when you are first inserting the password into the database (that way, you aren't storing the actual password, just a hash). Then, when your user logs in with their username, look in the database for a user with that username. If you find a user with that username, then you use password_verify to check that the $password variable matches the hash that was stored in the database with that user.
Check out this answer to a similar question to see a fleshed out example of login code.
I am making a registration and login form, which asks for the user's email and password. In my registration file I hashed the password provided by the user, and stored it in the database, with the function password_hash. In my login form I tried to verify the password provided by the user with the stored hashed password in the database, but it fails. I used the password_verify function. Here is a snippet of the registration code:
Registration file snippet
if(!isset($error)){
//hash the password
$hashedpassword = password_hash($_POST['password'], PASSWORD_DEFAULT);
echo $hashedpassword;
try {
$sql = "INSERT INTO users (mail, password, province) VALUES (:mail, :password, :province)";
$stmt = $db->prepare($sql);
//Bind variables
$stmt->bindValue(':mail', $mail);
$stmt->bindValue(':password', $hashedpassword);
$stmt->bindValue(':province', $province);
//Execute the statement and insert the new account.
$result = $stmt->execute();
//If the signup process is successful.
if($result){
echo $hashedpassword;
exit;
}
}
catch(PDOException $e) {
$error[] = $e->getMessage();
}
}
Hashed passwords in database
For these passwords I get the following hashed passwords, which are stored in the database:
football:
$2y$10$q0Y8Mfdl75Dt8op7WaqQM.t5y4LMO6gfYwmbycL1xRMiUUQu8dtWm$2y$10$q0Y8Mfdl75Dt8op7WaqQM.t5y4LMO6gfYwmbycL1xRMiUUQu8dtWm
cricket:
$2y$10$Pyoz1XC0skRjHLjxHdrYYeYplY98w4uOp23QpZb/VNN0y41/6YPJC$2y$10$Pyoz1XC0skRjHLjxHdrYYeYplY98w4uOp23QpZb/VNN0y41/6YPJC
The type for the password row is varchar(255) and the collation is utf8mb4_general_ci The passwords are stored like this:
$2y$10$q0Y8Mfdl75Dt8op7WaqQM.t5y4LMO6gfYwmbycL1xRM...
$2y$10$Pyoz1XC0skRjHLjxHdrYYeYplY98w4uOp23QpZb/VNN...
When I hover over the passwords it says 'Original length 60'.
Login file snippet
This is a snippet of my login file code:
$mail = htmlspecialchars_decode($_POST['mail'], ENT_QUOTES);
if(!filter_var($mail, FILTER_VALIDATE_EMAIL) and !empty($_POST['mail'])) {
$error[] = 'Please enter a valid email address';
}
$stmt = $db->prepare('SELECT mail, password FROM users WHERE mail = :mail');
$stmt->execute(array(':mail' => $mail));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if(!empty($row['mail'])){
$error[] = 'Email provided is good.';
}
$password = $_POST['password'];
$stmt = $db->prepare('SELECT password FROM users WHERE password = :password');
$stmt->execute(array(':password' => $password));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$checkpass = $row['password'];
echo $checkpass;
if(password_verify($password, $row['password'])) {
$error[] = 'Password provided is good.';
}
Checking whether the email can be found in the database works fine, as it gives me the error message (which I need to change to a normal message).
But I can't get the password verification working. I tried to see what the code pulls out the database with $checkpass = $row['password']; and
echo $checkpass;
But it doesn't return anything (maybe because it only returns a 0 or 1 value?).
Maybe it has to do something with the way I try to select the hashed password out of the database? Or the way I insert them in the database, or the MySQL table options? It may be a simple fix but I tried many different things and I couldn't get it to work.. Hope you guys can help!
The second query seems to be useless since in the first query you already select the mail and password fields. So you should just need to execute the first query, check if the user is valid and then check the password with the password_verify method.
Your second query fails (probably) because in the condition you pass the cleartext but in the DB there is the hashed password so you will never find anything. To check print the second query before the execution.
Before executing query for password check in login you should create hashed password for the input password and that hashed password need to be compared
Can someone please tell me how i am suppose to verify a hashed password when someone is logging in?
here is my registration code:
$db_password = password_hash($password, PASSWORD_DEFAULT);
// Enter info into the Database.
$info2 = htmlspecialchars($info);
$sql = mysql_query("INSERT INTO users
(first_name, last_name, email_address, username, password, signup_date)
VALUES('$first_name', '$last_name',
'$email_address', '$username',
'$db_password', now())")
or die (mysql_error());
this is my check user code run at login . .
$hash = password_hash($password, PASSWORD_DEFAULT);
// check if the user info validates the db
$sql = mysql_query("SELECT *
FROM users
WHERE username='$username'
AND password='$hash'
AND activated='1'");
$login_check = mysql_num_rows($sql);
i can not figure it out.
Your verification is wrong...you are hashing the password all over again, which will result in a brand-new salt...thus a completely different hash value. When passwords are hashed (correctly), they use a salt (random string) that is sufficiently long to prevent a rainbow attack. password_hash is doing all of this behind the scenes for you.
However, this means you have to make sure to use the same salt in order to verify the password by storing it along with the hash. In the case of the code you are using, it's doing this part for you and the salt is the prefix of the result of password_hash.
When the user logs in, you need to do:
if( password_verify($loginPasswordText, $hashStoredInDb) ) {
//SUCCESS
}
No need to password hashing again at login time, Use simply password_verify() function to verify your stored password & given password at login moment. See more about Password Hashing API here http://php.net/manual/en/ref.password.php
For now Try like this,
<?php
// this is the example hashed password that you have to select from Database.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';
if (password_verify('password_given_at_login', $hash)) {
echo 'Password is valid!';
} else {
echo 'Invalid password.';
}
?>
I'm trying to store an encrypted password in MySQL and as for the register part it works as it should how ever when i try to do the login things go south.
I can not verify $_POST['password'] against the hash stored in MySQL.
I have no idea what I'm doing wrong.
Here is my register.php which works as it should:
register.php (working)
$post_password = mysqli_real_escape_string($_POST['password']);
$password_hash = password_hash($post_password, PASSWORD_BCRYPT);
mysqli_query goes here...
login.php (not working)
$con = mysqli_connect("XXX","XXX","XXX","XXX");
$post_username = mysqli_real_escape_string($con,$_POST['username']);
$post_password = mysqli_real_escape_string($con,$_POST['password']);
// Getting the stored Hash Password from MySQL
$getHash = mysqli_fetch_assoc(mysqli_query($con, "SELECT * FROM anvandare WHERE username = '$post_username'"));
$got_Hash = $getHash['password'];
// Checking if what the user typed in matches the Hash stored in MySQL
// **This is where it all goes wrong**
if (password_verify($post_password, $got_Hash)) {
echo "The posted password matches the hashed one";
}
else {
echo "The posted password does not match the hashed one";
}
When I run the code above I get the "Correct password" message by just entering the username and leaving the password field out.
What am I missing?
Actually you need to make sure that you are allowing more than 100 characters in your password column so that all the hashed password can be saved in the field. This was also happening with me, the script was correct and everything was working fine but the only mistake I was doing was that I didn't allow more than 40 characters in the password field which was the biggest error. After incrementing the maximum limit from 40 to 100, everything is working fine:)