This question already has answers here:
How to use PHP's password_hash to hash and verify passwords
(5 answers)
Closed 2 years ago.
I have a password being hashed and saved in to a SQL database with the following code:
$passHash = password_hash($password, PASSWORD_DEFAULT);
It is saved in to a field called 'password' with the type VARCHAR(255)
I then use the following code to log the user in
$dbconn = OpenCon();
$username = $_POST['usernameInput'];
$password = $_POST['passInput'];
$passHash = password_hash($password, PASSWORD_DEFAULT);
$school = $_POST['schoolInput'];
$sqlstmnt2 = 'SELECT * FROM users WHERE username = :username AND school = :school';
$stmtUsr2 = $dbconn -> prepare($sqlstmnt2);
$stmtUsr2 -> bindValue(':username', $username);
$stmtUsr2 -> bindValue(':school', $school);
$stmtUsr2 -> execute();
$rows = $stmtUsr2 -> fetchAll();
$n = count($rows);
if($n<1 or !password_verify($rows[0]['password'], $passhash)) {
echo 'No user account exists. Please check your credentials'."<br>";
}
else{
$_SESSION['username'] = $username;
header("Location: home.php");
}
When I run it and enter a details I know to be correct, the password_verify function is not returning that they are the same. What am I doing wrong?
If we break down the code, and look at the main flow without the details, we have something like this:
$passwordFromUserInput = getPasswordFromUserInput(); // $password in your code
$passHash = password_hash($passwordFromUserInput, PASSWORD_DEFAULT);
$passwordHashFromDb = getPasswordHashFromDb(); // $rows[0]['password'] in your code
if ( password_verify($passwordHashFromDb, $passHash) ) {
// success
}
(I'm assuming that although the database column is called password, it isn't actually storing the raw password, which would defeat the purpose of hashing it!)
But if we look at the signature of password_verify in the PHP manual, it looks like this:
password_verify ( string $password , string $hash )
You're passing in two hashes, but it wants a password (the one the user attempted to log in with) and a hash (the one you've stored). So the corrected version of the simplified code is this:
$passwordFromUserInput = getPasswordFromUserInput(); // $password in your code
$passwordHashFromDb = getPasswordHashFromDb(); // $rows[0]['password'] in your code
if ( password_verify($passwordFromUserInput, $passwordHashFromDb) ) {
// success
}
Or more succinctly:
if ( password_verify($_POST['passInput'], $rows[0]['password']) ) {
// success
}
The key to understanding this is that the function is not just comparing two strings. It's using information stored in the original hash (including a random "salt" string) to re-calculate a new hash from the user's input.
Related
This question already has answers here:
Can I mix MySQL APIs in PHP?
(4 answers)
How can I get useful error messages in PHP?
(41 answers)
Closed 3 years ago.
UPDATE: I just want to update to share how I finally solved the issue I was having with the password_hash function in case others run into the same problem. I did not have the size of my password table long enough to accommodate the size of the hashed password, which worked fine for MD5. After changing the password table to 255 characters, these functions worked how they should.
I am adding users to my database and trying to use password_hash with the password they submit. Once added, users need to be able to log in. I am trying to verify the password with verify_password but it keeps coming back false.
I have been able to add users with password_hash but unable to log in with added users using the password_verify method. Strangely, if I add a user with MD5 within phpmyadmin, I can log them in no problem using md5($password). If I add users with md5 through my code, even if the passwords match, I am unable to log them in with this method.
I have been searching and searching and can't seem to figure out what I am doing wrong.
This was meant as a test to see if I can log in users. I know MD5 is not a great way. If I manually add a user and use the MD5 method in phpmyadmin, this code works:
if(md5($password) === $hashed) {
// log in user code
}
When adding the password, I am encrypting it like this:
$password = md5($_POST['password']);
Then I add it to an array and insert it into the database. Once again, this is just a test.
When I try using the password_hash function, which is what I would like to do, password_verify does not work. This is what I am trying to do.
INSERT FUNCTION:
function insertAgent($conn) {
$firstname = testdata($_POST['firstname']);
$middlename = testdata($_POST['middlename']);
$lastname = testdata($_POST['lastname']);
$phone = testdata($_POST['phone']);
$email = testdata($_POST['email']);
$position = testdata($_POST['position']);
$agency = testdata($_POST['agency']);
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
$agentArray[] = array(
'AgentId' => '',
'AgtFirstName' => $firstname,
'AgtMiddleInitial' => $middlename,
'AgtLastName' => $lastname,
'AgtBusPhone' => $phone,
'AgtEmail' => $email,
'AgtPosition' => $position,
'AgencyId' => $agency,
'password' => $password
);
foreach ($agentArray as $array) {
$query = "INSERT INTO agents";
$result = $conn->query($query);
$query .= " (`".implode("`, `", array_keys($agentArray[0]))."`) VALUES";
foreach ($agentArray as $array) {
$query .= " ('".implode("', '", $array)."'),";
}
$query = substr($query,0,-1); // remove last comma
$result = mysqli_query($conn, $query) or die(mysql_error());
LOGIN:
if(!empty($_POST["login"])) {
$useremail = trim($_POST['useremail']);
$password = trim($_POST['password']);
$pass_query = mysqli_query($conn, "SELECT password FROM agents WHERE AgtEmail='$useremail'");
$pass = mysqli_fetch_assoc($pass_query);
$hashed = $pass['password'];
if(password_verify($password, $hashed)) {
$result = mysqli_query($conn, "SELECT * FROM agents WHERE AgtEmail='" . $useremail . "'");
$row = mysqli_fetch_assoc($result);
if(is_array($row)) {
$_SESSION["AgentId"] = $row['AgentId'];
}
} else {
$message = "<p class='errorForm'>Invalid Email or Password</p>";
}
}
The hashed version in the DB ($hashed) matches the md5 version from the user but it results in false unless I manually add it.
This question already has answers here:
Using PHP 5.5's password_hash and password_verify function
(4 answers)
Closed 3 years ago.
I am trying to process a password as md5 into the database, this is the concerned code:
include_once("config.php");
session_start();
if(isset($_POST['signup'])){
$name = $_POST['name'];
$email = $_POST['email'];
$pass = $_POST['pass'];
$insert = $pdo->prepare("INSERT INTO users (name,email,pass)
values(:name,:email,:pass) ");
$insert->bindParam(':name',$name);
$insert->bindParam(':email',$email);
$insert->bindParam(':pass',$pass);
$insert->execute();
}elseif(isset($_POST['signin'])){
$email = $_POST['email'];
$pass = $_POST['pass'];
$select = $pdo->prepare("SELECT * FROM users WHERE email='$email' and pass='$pass'");
$select->setFetchMode();
$select->execute();
$data=$select->fetch();
if($data['email']!=$email and $data['pass']!=$pass) {
echo "invalid email or pass";
}
elseif($data['email']==$email and $data['pass']==$pass) {
$_SESSION['email']=$data['email'];
$_SESSION['name']=$data['name'];
header("location:profile.php");
}
}
What length in the db would be appropriate to store this hashed password?
And how do I use this:
$hashed_password = password_hash($pass, PASSWORD_DEFAULT);
var_dump($hashed_password);
and the if statement if the password was ok?
Its really quite simple once you read the manual or see an example in a tutorial. See comments in the code for details
<?php
include_once("config.php");
session_start();
if(isset($_POST['signup'])){
$name = $_POST['name'];
$email = $_POST['email'];
// at signup you hash the user provided password
$pass = password_hash($_POST['pass'], PASSWORD_DEFAULT);
$insert = $pdo->prepare("INSERT INTO users (name,email,pass)
values(:name,:email,:pass) ");
$insert->bindParam(':name',$name);
$insert->bindParam(':email',$email);
$insert->bindParam(':pass',$pass); // this stores the hashed password
$insert->execute();
}elseif(isset($_POST['signin'])){
$email = $_POST['email'];
$pass = $_POST['pass'];
// as the password on the DB is hashed you cannot use the
// plain text password in the SELECT here as it wont match
$select = $pdo->prepare("SELECT * FROM users WHERE email=:email");
// no idea what this was doing
//$select->setFetchMode();
$select->bindParam(':email',$email);
$select->execute();
$row = $select->fetch(PDO::FETCH_ASSOC);
// verify the plain text password against the
// hashed value from DB in $row['pass']
if( password_verify($pass, $row['pass']) ){
$_SESSION['email'] = $data['email'];
$_SESSION['name'] = $data['name'];
header("location:profile.php");
exit;
} else {
echo "invalid email or pass";
}
}
And as to the length of the column in the database that you need to hold this hashed value, it is documented in the manual
The following algorithms are currently supported:
PASSWORD_DEFAULT - Use the bcrypt algorithm (default as of PHP 5.5.0). Note that this constant is designed to change over time as new and stronger algorithms are added to PHP. For that reason, the length of the result from using this identifier can change over time. Therefore, it is recommended to store the result in a database column that can expand beyond 60 characters (255 characters would be a good choice).
PASSWORD_BCRYPT - Use the CRYPT_BLOWFISH algorithm to create the hash. This will produce a standard crypt() compatible hash using the "$2y$" identifier. The result will always be a 60 character string, or FALSE on failure.
This question already has answers here:
What is the difference between single-quoted and double-quoted strings in PHP?
(7 answers)
Closed 6 years ago.
i'm working on a passowrd reset but the issue i'm having is that when ever the password is about to get update for some reason it changes here is my code
>?php
if ($password == $confirmpassword)
{
echo "$password";
echo "</br>";
//has and secure the password
$npassword = password_hash('$password', PASSWORD_BCRYPT, array('cost' => 10));
echo "$npassword";
// Update the user's password
$query = $conn->prepare('UPDATE users SET password = :password WHERE email = :email');
$query->bindParam(':password', $npassword);
$query->bindParam(':email', $email);
$query->execute();
$conn = null;
echo "Your password has been successfully reset.";
}
else
echo "Your password's do not match.";
}
?>
example im trying to use demo123 as password when i echo $password i do get demo123, when i echo $npassword i get a code and when i manually do
>?php $npassword = password_hash('demo123', PASSWORD_BCRYPT, array('cost' => 10));?>
i get another hash Now this has does work if i add it manually if i use the variable $password i get another code wrong by the way cause i cant login but if i do it manual and update it then demo123 works.
what am i doing wrong, I'm a newbie
If you want to use variables in strings you have to use double-quotes (").
In your case though, since you're using variables exlusively and not adding anything to them, you can just remove your quotes:
$npassword = password_hash($password, PASSWORD_BCRYPT, array('cost' => 10));
Also, since cost already defaults to 10 you can just omit that aswell:
$npassword = password_hash($password, PASSWORD_BCRYPT);
password_hash results are always different, you can't query mysql by generated hash, you need to get the user and do password_verify ($password, $hash); instead
where $password is 'demo123' and $hash is password column value from DB
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
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
My code is actually working but it's not at all secure, I don't want to use MD5 as it's not all that secure. I've been looking up password hashing but I'm not sure how I would incorporate it into my code.
Login:
require_once __DIR__.'/config.php';
session_start();
$dbh = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_USERNAME, DB_USERNAME, DB_PASSWORD);
$sql = "SELECT * FROM users WHERE username = :u AND password = :p";
$query = $dbh->prepare($sql); // prepare
$params = array(":u" => $_POST['username'], ":p" => $_POST['password']);
$query->execute($params); // execute
$results = $query->fetchAll(); // then fetch
//hash passwords pls
if (count($results) > 0 ){
$firstrow = $results[0];
$_SESSION['username'] = $firstrow['username'];
echo "Hello $username you have successfully logged in";
//header ("location:.php");
}
else{
echo "Login Has Failed";
return;
}
Register:
$dbh = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_USERNAME, DB_USERNAME, DB_PASSWORD);
$username = $_POST["username"];
$email = $_POST["email"];
$password = $_POST["password"];
$stmt = $dbh->prepare("insert into users set username='".$username."', email='".$email."', password='".$password."' ");
$stmt->execute();
echo "<p>Thank you, you are registered</p>";
Could anyone show me how to incorporate it into the code I have?
Just use a library. Seriously. They exist for a reason.
PHP 5.5+: use password_hash()
PHP 5.3.7+: use password-compat (a compatibility pack for above)
All others: use phpass
Don't do it yourself. If you're creating your own salt, YOU'RE DOING IT WRONG. You should be using a library that handles that for you.
$dbh = new PDO(...);
$username = $_POST["username"];
$email = $_POST["email"];
$password = $_POST["password"];
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $dbh->prepare("insert into users set username=?, email=?, password=?");
$stmt->execute([$username, $email, $hash]);
And on login:
$sql = "SELECT * FROM users WHERE username = ?";
$stmt = $dbh->prepare($sql);
$result = $stmt->execute([$_POST['username']]);
$users = $result->fetchAll();
if (isset($users[0]) {
if (password_verify($_POST['password'], $users[0]->password) {
// valid login
} else {
// invalid password
}
} else {
// invalid username
}
About making your code more secure:
You should ALWAYS validate user entries, even from a POST method which can be changed by using firebug before submitting the form. As you are inserting the user input in a query, it's much more important.
About your question in general
As I advised you in the comment, use PHPass or already made APIs which will do the job for you.
You'll hash the username, pass and salt at account creation time and insert the hash in the database.
At authentication time, you'll regenerate a hash with the given login + password input and the information you added to generate the salt.
If both generated hashes match, then the user is authenticated.
EDIT: Yes password_hash is good also.
Basically, you have two options, varying in complexity:
Store a Hash of the registered user's password, using a hashing algorithm of your choice (more into this later).
create a random salt (a constant, secret string) to be used together with the user's password, to create the hash as stated above and then store that hash in the DB.
When you retrieve the user record, you compare the hash computed from the provided password, with the hash stored in the DB.
Example:
$HashedPass = hash('sha512', $password);
or with a pre-defined SALT:
$HashedPass = hash('sha512', $password.SALT_STRING);
Store this into the DB as you did before.
Authenticating in done similarly:
$HashedPass = hash('sha512', $password.SALT_STRING);
and then retrieve from the DB based on that hash comparison to the stored one.
Now, I'd like to address your concerns about Hashing algorithms:
You dont have to use md5, you can as well use more secure hashing algorithms, refer to a comment here:
PHP's hash function
One suggestion is to use sha512 algorithm.
Most importantly, you should understand that hash is a one way conversion - there is no practical way to reverse engineer the original password from the hash alone, only perhaps finding alternative strings, which produce the same hash string.
I hope you find using a strong Hash algorithm, along with a Salt to mitigate the damage of a stolen Hash DB, good enough for your needs.