Verify password hash using password_verify and MySQL - php

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:)

Related

PHP password_verify always returning false even when hardcoded [duplicate]

This question already has answers here:
How to use PHP's password_hash to hash and verify passwords
(5 answers)
Closed 1 year ago.
Here's my code:
function login() {
//Declare variables
$username = $_POST["login"];
$password = $_POST["password"];
$client = $_POST["clients"];
//QueryDB
$servername = "localhost";
$SQLUsername = "XXXX";
$SQLPassword = "XXXX";
$dbname = "XXXX";
$conn = new mysqli($servername, $SQLUsername, $SQLPassword, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
//Set query then run it
$sql = "SELECT * FROM Users WHERE Username ='$username'";
$result = $conn->query($sql);
$row = $result->fetch_array(MYSQLI_ASSOC);
//Verify Password
if ($result->num_rows === 1) {
if (password_verify($password, $row['Password'])) {
//Build XML request
$XMLRequest = "<?xml version='1.0'?><Login><Client>".$client."</Client><LoginDetails><Username>".$username."</Username><Password>".$newhash."</Password></LoginDetails></Login>";
//Build URL
$ReplacedValues = array("NewType" => "login", "NewHash" => $XMLRequest);
$NewString = strtr($GLOBALS["params"], $ReplacedValues);
$NewUrl = $GLOBALS["link"].$NewString;
//Post to Server
header('Location: '.$NewUrl);
}
else {
echo "Password is wrong"."<br>";
echo $password."<br>";
echo $row['Password'];
}
} else {
echo "more then 1 row";
}
mysqli_close($conn);
}
My issue is that even if I hard code my password variable and Hash variable to their respective values the if condition returns false. Any idea why? The page does when it loads, loads the else condition to show me the user input password and the correct hash value from the DB. My DB is set to CHAR(255) for the password.
UPDATE**
Here is my C# discussed in the comments. This is not the complete code just up to the part of the insert statement for the DB. I am able to insert into the SQL server DB just fine.
public static string WebsiteRegister(XmlDocument XMLBody)
{
//Get SQL connection string
XmlNodeList XMLNodes = SQLConnectionMethods.EstablishSQLServerConnection("SQL");
string ConnectionString = XMLNodes.Item(0).ChildNodes[0].InnerText;
string UserName = XMLNodes.Item(0).ChildNodes[1].InnerText;
string Password = XMLNodes.Item(0).ChildNodes[2].InnerText;
//Open connnection
SqlConnection cnn = new SqlConnection(ConnectionString);
SQLConnectionMethods.OpenSQLServerConnection(cnn);
try
{
string username = XMLBody.SelectSingleNode("register/registerdetails/username").InnerText;
string pass = XMLBody.SelectSingleNode("register/registerdetails/password").InnerText;
string fname = XMLBody.SelectSingleNode("register/registerdetails/firstname").InnerText;
string lname = XMLBody.SelectSingleNode("register/registerdetails/lastname").InnerText;
string email = XMLBody.SelectSingleNode("register/registerdetails/email").InnerText;
string accountRef = XMLBody.SelectSingleNode("register/registerdetails/accountreference").InnerText;
string client = XMLBody.SelectSingleNode("register/client").InnerText;
//Build Query string
string queryString = $"Insert into [dbo].[UserAccounts] (AccountReference, FirstName, LastName, Email, Username, Pass, Client) values ('{accountRef}', '{fname}', '{lname}', '{email}', '{username}', '{pass}', '{client}')";
//Process request
using (SqlCommand myCommand = new SqlCommand(queryString, cnn))
{
string Result = (string)myCommand.ExecuteScalar();
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

Why are my variables coming up as undefined, des?

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.

Password is not verified using function password_verify

I think i have hashed password using function PASSWORD directly from mysql database(am i doing wrong here?). And i am trying to verify that password with this code:
if($submit)
{
$first=$_POST['first'];
$password=$_POST['password'];
$hash="*85955899FF0A8CDC2CC36745267ABA38EAD1D28"; //this is the hashed password i got by using function PASSWORD in database
$password=password_verify($password,$hash);
$db = new mysqli("localhost", "root","","learndb");
$sql = "select * from admin where username = '" . $first . "' and password = '". $password . "'";
$result = $db->query($sql);
$result=mysqli_num_rows($result);
if($result>0)
{
session_start();
$_SESSION['logged_in'] = true;
session_regenerate_id(true);
header("Location:loginhome.php");
}
}
But the password is not matching. What am i missing here?
UPDATE:
After all the suggestions i have used password_hash from php code to store into database.
$db = new mysqli("localhost", "root","","learndb");
$password=password_hash('ChRisJoRdAn123',PASSWORD_DEFAULT);
$sql="INSERT INTO admin (username,password)values('ChrisJordan','$password')";
$db->query($sql);
still the password is not matching.
One cannot search for a salted password hash in a database. To calculate the hash you need the password_hash() function as you already did correctly in your insert statement.
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_DEFAULT);
To check a password, you first need to search by username only (used a prepared query to avoid sql injection):
$sql = 'select * from admin where username = ?';
$db->prepare($sql);
$db->bind_param('s', $first);
When you finally got the stored hash from the database, it can be checked like this:
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
password_verify is a boolean function which return either true or false. In your code, after getting value of password from Post param, you doing this operation
$password=password_verify($password,$hash);
which changes the $password value to true or false and that boolean value stored in $password you are using in mysql select statement
$sql = "select * from admin where username = '" . $first . "' and password = '". $password . "'";
Another thing is it might be possible that the hashed/salted password you are using is not the correct hashed value of the password you are using.
Update: Try this
$cost = [
'cost' => 15,
];
$hash_password = password_hash('ChRisJoRdAn123', PASSWORD_BCRYPT, $cost);
before any db operation, change your password field varchar length to >=64
$sql = "INSERT INTO admin (username,password)values('ChrisJordan','".$hash_password."')";
After insert operation, execute the select statement with the user
$sql = "select * from admin where username = 'ChrisJordan'";
after this fetching hased password and password from the post parameter, you will need to verify both passwords using password_verify
if (password_verify(validate($_POST['password']), $hash_password_from_db)) {
echo "Valid Password";
}else{
echo "Invalid Password";
}
You must use password_hash to encode passwords verified with password_verify.
The MySQL function PASSWORD is something entirely different. It is used for encoding passwords specific to MySQL authentication. (MySQL specifically recommends against using PASSWORD for anything other than MySQL authentication.)
The two use different hashing algorithms, present their output in different formats, and are generally not compatible with each other.
The typical way to use password_hash and password_verify is:
$hash = password_hash($password, PASSWORD_DEFAULT);
//Store $hash in your database as the user's password
//To verify:
//Retrieve $hash from the database, given a username
$valid = password_validate($password, $hash);
The problem in your code is that you're doing this:
$password=password_verify($password,$hash);
$sql = "select * from admin where username = '" . $first . "' and password = '". $password . "'";
password_verify returns a boolean (whether the password and hash matched). Instead, you need to retrieve the hash from the database and match the entered password with that hash.
This is too long for a comment.
Seeing that this question has yet to contain a green tick next to any of the answers, am submitting the following in order to point out probable issues.
I noticed that you are trying to move over from MD5 to password_hash() - password_verify().
Your other question Switching from md5 to password_hash
What you need to know is that MD5 produces a 32 character length string, as opposed to password_hash() being a 60 length.
Use varchar(255).
If you kept your password column's length to 32, then you will need to clear out your existing hashes from that column, then ALTER your column to be 60, or 255 as the manual suggests you do.
You will need to clear out all your existing passwords, ALTER your column, create a new hash, then try your login code again.
I see this in your code:
"*85955899FF0A8CDC2CC36745267ABA38EAD1D28"; //this is the hashed password i got by using function PASSWORD in database
This string *85955899FF0A8CDC2CC36745267ABA38EAD1D28 is 40 long, which is too short and has been cut off.
This tells me that your column's length is 40, instead of 60, or again as the manual suggests, 255.
MD5 reference:
http://php.net/manual/en/function.md5.php
Returns the hash as a 32-character hexadecimal number.
Reference for password_hash():
http://php.net/manual/en/function.password-hash.php
The result will always be a 60 character string, or FALSE on failure.
To ALTER your column, here is a reference link:
http://dev.mysql.com/doc/refman/5.7/en/alter-table.html
Also make sure that your form contains a POST method and that the inputs bear the matching name attributes and that no whitespace gets introduced.
You can use trim() to get rid of those.
Add error reporting to the top of your file(s) which will help find errors.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Then the rest of your code
Sidenote: Displaying errors should only be done in staging, and never production.
as well as or die(mysqli_error($db)) to mysqli_query().
Edit:
What you need to do is fetch an array and get the match on that.
$sql = "select * from admin where username = '".$first."' and password = '".$password."' ";
$result = $db->query($sql);
if ($result->num_rows === 1) {
$row = $result->fetch_array(MYSQLI_ASSOC);
if (password_verify($password, $row['password'])) {
//Password matches, so create the session
// $_SESSION['user']['user_id'] = $row['user_id'];
// header("Location:/members");
echo "Match";
}else{
echo "The username or password do not match";
}
}
Another possible solution:
$query = "SELECT * from admin WHERE username='$first'";
$result = $db->query($query);
if($result->num_rows ===1){
$row = $result->fetch_array(MYSQLI_ASSOC);
if (password_verify($password, $row['password'])){
echo "match";
} else {
$error = "email or Password is invalid";
echo $error;
}
}
mysqli_close($db); // Closing Connection

PHP hash_password function

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' ;
}

Need help making login page with salts

Alright, I'm trying to make a login page. It seems that all of the pages worked pretty good- until I added salts. I don't really understand them, but doing something as basic as I am shouldn't be to hard to figure out. Here's "loginusr.php":
<html>
<body>
<?php
//form action = index.php
session_start();
include("mainmenu.php");
$usrname = mysql_real_escape_string($_POST['usrname']);
$pass = $_POST['password'];
$salt = $pass;
$password = sha1($salt.$pass);
$con = mysql_connect("localhost", "root", "g00dfor#boy");
if(!$con)
{
die("Unable to establish connection with host. We apologize for any inconvienience.");
}
mysql_select_db("users", $con) or die("Can't connect to database.");
$select = "SELECT * FROM data WHERE usrname='$usrname' and password='$password'";
$query = mysql_query($select);
$verify = mysql_num_rows($query);
if($verify==1)
{
$_SESSION["valid_user"] = $usrname;
header("location:index.php");
}
else
{
echo "Wrong username or password. Please check that CAPS LOCK is off.";
echo "<br/>";
echo "Back to login";
}
mysql_close($con);
?>
</body>
</html>
I used the command echo $password; to show me if the password in the database matched with the script. They did. What am I doing wrong?
It seems like you've misunderstood salts, since you're setting $salt to be the password.
A salt should be a completely random string that's stored in a user record along with the password hash. A new unique salt should be generated for every user. So you need to add a new column to your database, called "password_salt" or similar.
Rather than trying to use the password in the SELECT query and see if you get any records, you actually need to just SELECT using the username/user_id in order to get the password hash and salt so that you can then use those to determine if the user entered the correct password.
When you sign up new users you should add the fields with values like this,
<?php
// This is registeruser.php
$salt = substr(sha1(uniqid(rand(), true)), 0, 20);
$pass = $_POST['password'];
$pass_to_store = hash("sha256", $salt.$pass);
// Then issue a DB query to store the $salt and $pass_to_store in the user record.
// Do not store $pass, you don't need it.
// e.g. INSERT INTO users ('username', 'password_salt', 'password_hash') VALUES (:username, :salt, :pass_to_store);
?>
Then to check the password is the same when logging in, you do something like this,
<?php
// This is loginuser.php
$user = // result from SQL query to retrieve user record
// e.g. SELECT password_hash, password_salt FROM users WHERE username='from_user'
$salt_from_db = $user['password_salt'];
$pass_from_db = $user['password_hash'];
if ($pass_from_db == hash("sha256", $salt_from_db.$_POST['password'])
{
// Password matches!
}
?>
Don't forget to sanitize user inputs and anything you're putting into your database. You might want to look into using prepared statements instead of having to remember to use mysql_real_escape_string all the time.
It looks like you're salting with the same password? Normally a salt would be a random key that is specific to your site that you prepend to the password input, which it looks like you're doing fine. Just make sure you're using that same salt for checking that you use when the password is created.
Also, to use sessions properly you need to have session_start before anything is output to the page:
<?php
session_start();
?>
<html>
<body>
...
A salt is a random value to prevent an attacker from just looking up the source of a hash in table generated based on common passwords. (Using the username as salt is obviously not a good idea as it only adds very little entropy).
So you need to store the salt in the database and read it from the database in order to calculate the salted password hash for comparison with the stored value.
You misspelled username a couple of times, is it misspelled in the database, too?

Categories