PHP password_verify - php

I am working on making a login section for my project website using PHP, but for some reason, verify_password won't return true, even when I am giving the correct password. No idea what I am doing wrong here.
Here is the code that I use to add the user to the MySQL table:
$password= $_POST['password'];
$hash = password_hash('$password', PASSWORD_DEFAULT);
// I know this isn't inject proof
$res = $conn->prepare('INSERT INTO login (SSN, UserName, passhash) VALUES (:SSN, :UserName, :passhash)');
$res->bindValue(':SSN', $_POST['UserName']);
$res->bindValue(':UserName', $_POST['UserName']);
$res->bindValue(':passhash', $hash);
$res->execute();
It stores the hash in a varchar(60)
Here is the code that takes the password, and verifies it against the hash:
$userName = $_POST['UserName'];
$password= $_POST['password'];
// I doubt this is inject proof
$res = $conn->prepare("select passhash from login where UserName='$userName'");
//$res->bindValue(':SSN', $_POST['UserName']);
//$res->bindValue(':UserName', $_POST['UserName']);
//$res->bindValue(':hash', $hash);
$res->execute();
$result = $res->fetch();
if(!empty($result) && password_verify($password, $result['passhash']))
What can I try next?

Single quotes prevent variable interpolation, so this encodes the literal string $password as the password:
$hash = password_hash('$password', PASSWORD_DEFAULT);
Just use the variable directly:
$hash = password_hash($password, PASSWORD_DEFAULT);

Related

Unable to extract password hash from database with prepared statements

EDIT: To clarify, I am unable to extract the hashed password from my database using prepared statements.
I'm trying to create a login system that uses prepared statements, password_hash and password_verify.
I have created the registering form that creates the user, with the hashed password using password_hash($_POST['password'], PASSWORD_DEFAULT);
This works properly.
However, I am now stuck on creating the login form.
I am trying to get the password hash that gets stored when a user registers but I cannot get it to work with prepared statements.
This is what I currently have.
<?php
require('db.php');
if(isset($_POST['submit'])) {
$stmt = $connect->prepare('SELECT user_name, user_password FROM `users` WHERE user_name = ?');
if($stmt) {
$username = $_POST['username'];
$password = $_POST['password'];
$stmt->bind_param('s', $username);
$stmt->execute();
}
}
?>
How do I use the data that I got from the select query? And how do I use it to verify the password?
I tried:
$stmt->store_result();
$stmt->bind_result($loginUsername, $hash);
That only stored the username, but not the password hash and I have no clue why.
Verifying the password would use this?
password_verify($password, $hash);
UPDATE
<?php
require('db.php');
if(isset($_POST['submit'])) {
$stmt = $connect->prepare('SELECT user_name, user_password FROM `users` WHERE user_name = ?');
if($stmt) {
$username = $_POST['username'];
$password = $_POST['password'];
$stmt->bind_param('s', $username);
$stmt->execute();
// Get query results
$result = $stmt->get_result();
// Fetch the query results in a row
while($row = $result->fetch_assoc()) {
$hash = $row['user_password'];
$username = $row['user_name'];
}
// Verify user's password $password being input and $hash being the stored hash
if(password_verify($password, $hash)) {
// Password is correct
} else {
// Password is incorrect
}
}
}
?>
Read this PHP MANUAL.Try this:
<?php
require('db.php');
if(isset($_POST['submit'])) {
$stmt = $connect->prepare('SELECT user_name, user_password FROM `users` WHERE user_name = ?');
if($stmt) {
$username = $_POST['username'];
$password = $_POST['password'];
$stmt->bind_param('s', $username);
$stmt->execute();
// Get query results
$stmt->bind_result($user_name,$hash);
$stmt->store_result();
// Fetch the query results in a row
$stmt->fetch();
// Verify user's password $password being input and $hash being the stored hash
if(password_verify($password, $hash)) {
// Password is correct
} else {
// Password is incorrect
}
}
}
?>
This is how I created my login system:
$stmt = mysqli_prepare($link,"SELECT user_email,user_password,user_firstname,user_lastname,user_role,username FROM users WHERE user_email=?");
mysqli_stmt_bind_param($stmt,"s",$email);
mysqli_stmt_execute($stmt);
confirmQuery($stmt);
mysqli_stmt_bind_result($stmt,$user_email,$user_password,$user_firstname,$user_lastname,$user_role,$username);
mysqli_stmt_store_result($stmt);
mysqli_stmt_fetch($stmt);
if(mysqli_stmt_num_rows($stmt) == 0)
relocate("../index.php?auth_error=l1");
else{
if(password_verify($password,$user_password)){
$_SESSION['userid'] = $user_email;
$_SESSION['username'] = $username;
$_SESSION['firstname'] = $user_firstname;
$_SESSION['lastname'] = $user_lastname;
$_SESSION['role'] = $user_role;
if(isset($_POST['stay-logged-in']))
setcookie("userid", $email, time() + (86400 * 30), "/");
relocate("../index.php?auth_success=1");
}else
relocate("../index.php?auth_error=l2");
}
mysqli_stmt_close($stmt);

Secure form handling using stmt prepare

The prepare function is not recognizing members that already exist in the DB and as a result, always calls the function NewUser() when it is supposed to go through the else statement? I believe this is because when I ask it to verify the password, it encounters an error, but I have no idea what I am doing wrong?
function NewUser(){
global $dbh;
$fullname = trim($_POST['fullname']); //at a minimus clear whitespace.
$username = trim($_POST['username']);
$email = trim($_POST['email']);
$user_password = trim($_POST['password']);
$options = [
'cost' => 12, //higher = more lower= less. you want it to take around 0.4 seconds for security reasons!
];
$hashed_password = password_hash($user_password, PASSWORD_DEFAULT, $options); // hashed password for storage!
$stmt = $dbh->prepare("INSERT INTO USERS(fullname, username, email, password) VALUES('$fullname', '$username', '$email', '$hashed_password')");
$stmt->bindValue(1,$fullname,PDO::PARAM_STR);
$stmt->bindValue(2,$username,PDO::PARAM_STR);
$stmt->bindValue(3,$email,PDO::PARAM_STR);
$stmt->bindValue(4,$user_password,PDO::PARAM_STR);
if($stmt->execute()){
echo "<div class= container>","<div class = \" col-md-2 connout slideInTop\">"," <span class = \"username_text\">$username</span>, <br> welcome to <br> the <br> <span class = \"vibecourt_text\">VIBECOURT</span> family! <br><br> You may <br> now sign in <br> below","</div>","</div>";
}
}
function SignUp(){
global $dbh;
//checking the 'user' name which is from index.php, is it empty or have some text
if(!empty($_POST['username'])){
$username = trim($_POST['username']);
$password = trim($_POST['password']);
$stmt = $dbh->prepare("SELECT * FROM USERS WHERE (username = ? AND password = ?)");
$stmt->bindValue(1, $_POST['username'],PDO::PARAM_STR);
$stmt->bindValue(2, $_POST['password'],PDO::PARAM_STR);
$stmt->execute();
$selected_row = $stmt->fetch(PDO::FETCH_ASSOC);
//check password agaisnt stored hash
if(!password_verify($password, $selected_row['password'])) {
NewUser();
}
else{
echo("<script>location.href = 'pages/home/home.php'</script>");
}
}
}
SignUp();
Updated Answer
In light of what transpired in comments... it appears the issue is further rooted far above where you are originally storing the hashed password into the database.
You say you are using a varchar(50), for a password_hash value. This is too short, and mysql is no doubt clipping the INSERT. This will result in hashes that can never be matched.
You should have a varchar(60) at the very minimum, but PHP.net states that this hash can grow over time, and using a varchar(255) is recommended.
In this bit:
$stmt = $dbh->prepare("SELECT * FROM USERS WHERE (username = ? AND password = ?)");
$stmt->bindValue(1, $_POST['username'],PDO::PARAM_STR);
$stmt->bindValue(2, $_POST['password'],PDO::PARAM_STR);
You are trying to match the hashed value in the database, with a user inputted password (which is not hashed).
You should simply remove the AND password = ? and bindValue for it. That way it pulls a matching username entry from the db, and THEN does password_verify to determine if the user inputted password, matches:
$username = trim($_POST['username']);
$password = trim($_POST['password']);
$stmt = $dbh->prepare("SELECT * FROM USERS WHERE username = ?");
$stmt->bindValue(1, $username, PDO::PARAM_STR);
$stmt->execute();
$selected_row = $stmt->fetch(PDO::FETCH_ASSOC);
if(!password_verify($password, $selected_row['password'])) {
NewUser();
}
Side note: Although I'm not sure you really WANT to make a new user if they simply typed in the wrong password??? Surely you would handle that differently. Telling them they entered a wrong password and should try again.
EDIT
Also in your NewUser function you have this:
$stmt = $dbh->prepare("INSERT INTO USERS(fullname, username, email, password)
VALUES('$fullname', '$username', '$email', '$hashed_password')");
It should be this:
$stmt = $dbh->prepare("INSERT INTO USERS(fullname, username, email, password)
VALUES(?, ?, ?, ?)");
// ...
$stmt->bindValue(4,$hashed_password,PDO::PARAM_STR);// <- use $hashed_password

Unable to use password_verify($password, $hash)

So I have a Registration page and a Login page, the registration page works perfectly fine but the Login page doesnt seem to work and I cant seem to figure it out.
My database seems to be working as I am able to echo out the hashed password onto the page of the login, it seems to have something to do with
password_verify()
Registration Page (Working)
<?php
include("assets/includes/conn.php");
$user = $_POST['username'];
$pass = $_POST['pass'];
$cPass = $_POST['c-pass'];
$email = $_POST['email'];
$options = [
'cost' => 11
];
if($pass == $cPass){
$stmt = $conn->prepare("INSERT INTO users (username, pass, email) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $user, $h_p, $email);
$user = $_POST['username'];
$h_p = password_hash($pass, PASSWORD_DEFAULT, $options)."\n";
$email = $_POST['email'];
$stmt->execute();
echo "Created";
echo $h_p;
$stmt->close();
$conn->close();
}
Login Page (Not working)
<?php
include("assets/includes/conn.php");
$username = $_POST['username'];
$password = $_POST['pass'];
$sql = "SELECT * FROM users WHERE username = '$username'";
$result = $conn->query($sql);
if ($result->num_rows == 1){
$row = $result->fetch_assoc();
$hash = $row['pass'];
if(password_verify($password, $hash)){
echo "Yes";
} else {
echo "No<br/>";
echo "" . $hash . "<br/>";
echo $password;
}
}
The problem here is that the \n in:
$h_p = password_hash($pass, PASSWORD_DEFAULT, $options)."\n";
^^
is (invisibly) adding a carriage return/linefeed at the end of your password/hash.
You can either remove it.
$h_p = password_hash($pass, PASSWORD_DEFAULT, $options);
or trim() it:
$h_p = password_hash($pass, PASSWORD_DEFAULT, $options)."\n";
$h_p = trim($h_p);
I honestly don't know why the manual on password_hash() doesn't make a mention about it and the usage of it for storing it in a database (or a file).
NOTE: What the docs haven't used here, was to assign a variable to the example, which is what was done in the question here. Some may think that using the example and assigning a variable to it will work; it won't; not for storing the hash and then verifying it after.
The example from the manual reads as:
echo password_hash("rasmuslerdorf", PASSWORD_DEFAULT)."\n";
But doing:
$var = password_hash("rasmuslerdorf", PASSWORD_DEFAULT)."\n";
will in fact (theoretically) contain a 61-length string (because of the concated linefeed character), instead of the intended 60 without the linefeed character.
So now you need to clear out your present hashes and start over with a new set of hashes.
Have a look at this sandbox code example
When run, it will output something like this:
$2y$10$494GPYzaynEkfYxE3wcAj.OtwBU3CCwTMXOHKbdJmOqwMXRmq6v1u
61
Just in case the URL's a 404 later on, here's the code for the above:
<?php
$foo = password_hash('mypass', PASSWORD_DEFAULT)."\n";
echo $foo;
echo strlen($foo);
On an added note; you should also use a prepared statement for your SELECT just as you did for the INSERT; it's much safer.

Hash verification error in php

I would like to verify my stored hashed passwords with the inputs that the users insert.
What theory says...
After read about the mechanism of password_hash and password_verify, I realized that, theoretically, the string that is inserted will be compared with a hash, which, at least in my case, is stored in the site db.
What is happening to me...
I register my users with password_hash and then to verify the login I use password_verify. If I am good and the code is right, this function should verify the input of the user (even if it's plain text(?) ) with the stored hash.
Let's see the code:
Registration code:
$passwordHash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 12));
Note: There is more code but I guess that this is the most important part so I decided to paste only this part.
Login code:
<?php
//controller!
require "../model/backend.php";
$username = $_POST['user'];
$password = $_POST['password'];
$dbcom = new dbInteraction;
$dbcom->admlog($username, $password);
$dbcom->conclose();
?>
Verification code:
$this->username = $username;
$this->password = $password;
//$this->pdo = $pdo;
//$adm = 1;
$myquery = 'SELECT username, password, isadmin FROM users WHERE username = :username';// AND password = :password';
$stmt = $this->pdo->prepare($myquery);
$stmt->bindParam(':username', $username, PDO::PARAM_STR);
$stmt->execute();
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if($user === false){
die('1Incorrect username / password combination!');
} else{
//Compare the passwords.
$dbpass = $user['password'];
echo $dbpass;
echo '<br>bd<br>input<br>';
echo $password;
$validPassword = password_verify($dbpass, $password);
echo '<br>debug <br>';
echo 'pre pass:<br>';
echo $validPassword;
if($validPassword){
//Provide the user with a login session.
$_SESSION['user_id'] = $user['username'];
$_SESSION['logged_in'] = time();
//header('Location: home.php');
exit;
}else{
die('<br>no pass--Incorrect username / password combination!');
}
}
Do I have some theoretical base problem in my code or it's just bad coded? I'm still trying to realize.
Thank you very much.
The problem was in the order of password_verify params.
It should be like $validPassword = password_verify($password, $dbpass);
or in generic words:
$validPassword = password_verify('String to verify', 'Saved password');
Special thanks to #JonStirling

hash generated on register not same as on login

I generate a hashed password on user registration but when trying to log in the hashed password generate is different so i cant log in
reg: (ill be adding checks and verification once i get hashed password working)
session_start();
require_once('connect.php');
$login = $_POST['login'];
$password = $_POST['password'];
$cpassword = $_POST['cpassword'];
if($login == '') {
echo "Email missing";
}
if($password == '') {
echo "Password missing";
}
if($cpassword == '') {
echo "Password missing";
}
if( strcmp($password, $cpassword) != 0 ) {
echo "Passwords do not match";
}
$stmt = $db->prepare("INSERT INTO members (Email, Password) VALUES (:login, :password)");
$stmt->bindValue( ":login", $login );
$stmt->bindValue( ":password", hash("sha512", $password, $salt));
$stmt->execute();
if ($stmt)
{
header("location: ?p=register-success");
exit();
}
login:
session_start();
include_once ('connect.php');
$Email = $_POST['Email'];
$Password = $_POST['Password'];
$stmt = $db->prepare("SELECT * FROM members WHERE Email = :Email AND Password = :Password");
$stmt->bindParam(":Email", $Email);
$stmt->bindParam(":Password", hash("sha512", $Password, $salt));
$stmt->execute();
$member = $stmt->fetch(PDO::FETCH_ASSOC);
if ($member)
{
$_SESSION['SESS_MEMBER_ID'] = $member['Member_ID'];
$_SESSION['SESS_POST_AS'] = $member['Post_As'];
$_SESSION['SESS_AUTH'] = $member['auth'];
session_write_close();
header('location: index.php');
} else {
header("location: ?p=login-failed");
}
my salt: (a fixed set of characters for testing only)
$salt = "Zo4rU5Z1YyKJAASY0PT6EUg7BBYdlEhPaNLuxAwU8lqu1ElzHv0Ri7EM6irpx5w";
i checked if they were the same by echoing the hashed password before they were submitted on a related note, once the hashed password is stored in my table it isnt the same as the one submitted on register the one in the table has ?? in place of some special characters
The third parameter to hash determines whether the output from the hash is raw, i.e. not encoded as hexadecimal. Your salt is truthy, so the output is raw, and your database is trying to encode it as a string.
You probably meant to use hash_hmac. But switch to Bcrypt anyways; a fixed salt isn’t that useful.
This is the prototype for the hash function
string hash ( string $algo , string $data [, bool $raw_output = false ] )
So you need to do something like this:
$saltedPwd = $password . $salt;
$hashedSaltedPwd = hash("sha512", $saltedPwd);
$stmt = $db->prepare("INSERT INTO members (Email, Password) VALUES (:login, :password)");
$stmt->bindValue( ":login", $login );
$stmt->bindValue( ":password", $hashedSaltedPwd);
$stmt->execute();
Then make similiar changes to yuor login page.

Categories