I am building a dashboard system, with Apache running on a raspberry pi, and pre-generating a password and its hash for all new users.
The line I used to do this is password_hash('Password1@', PASSWORD_DEFAULT)
.
Users are shown a password reset window when they first log in. I am able to successfully use password_hash()
and password_verify()
after the users click submit on this password reset page.
The first login works just fine but on any login attempt after logging out results in the password_verify()
failing.
What I Have Checked/Tried
- Set the password attribute in the database to
varchar(255)
. - A single user row is retrieved and I can return data from it.
PASSWORD_DEFAULT
andPASSWORD_ARGON2ID
both do this.
Things I Know
- Database is
utf8mb4_unicode_ci
. - The new password that users set are successfully pushed to the database.
- I have added an
if
statement to check that the new hash can be verified and it can be.
- I have added an
- Hash string matches what comes back in the
SELECT
, as it should. - I used the functions below on other projects, with PHP 7. This project is on PHP 8. (Could this be the issue?)
Password Reset Function
public function firstLoginUpdatePassword($username, $password, $confirm, $token)
{
if ($password != $confirm)
{
header("Location: first-login?mismatch&token=" . $token);
exit;
}
else
{
$newPassword = password_hash($password, PASSWORD_DEFAULT);
$token = bin2hex(openssl_random_pseudo_bytes(16));
try
{
$stmt = $this->con->prepare("UPDATE Account SET Password=:password, isFirstLogin=FALSE, Token=:token WHERE Username=:username");
$stmt->bindparam(":username", $username);
$stmt->bindparam(":password", $newPassword);
$stmt->bindparam(":token", $token);
if ($stmt->execute())
{
header("Location: home");
exit;
}
else
{
header("Location: first-login?error&token=" . $token);
exit;
}
}
catch (PDOException $ex)
{
echo $ex->getMessage();
}
}
}
Login Function
public function Login($user, $pwd)
{
try
{
$stmt = $this->con->prepare("SELECT Username, Password FROM Account WHERE Username=:username or Email=:username;");
$stmt->bindparam(":username", $user);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($stmt->rowCount() == 1)
{
if (password_verify($pwd, $row['Password']))
{
try
{
$stmt = $this->con->prepare("UPDATE Account SET LastLogin=CURRENT_TIMESTAMP WHERE Username=:username;");
$stmt->bindparam(":username", $row['Username']);
if ($stmt->execute())
{
$_SESSION['userSession'] = $row['Username'];
return true;
}
else
{
header("Location: login?error-other");
exit;
}
}
catch (PDOException $ex)
{
echo $ex->getMessage();
}
}
else
{
header("Location: login?error-credential");
exit;
}
}
else
{
header("Location: login?error-login");
exit;
}
}
catch(PDOException $ex)
{
echo $ex->getMessage();
}
}
CodePudding user response:
The solution was somewhere in the file encoding. There was a mixture of encodings on my PHP files on the server. I re-encoded all files, recursively, to UTF-8 and the issue is gone now.