Evan Edwards
Evan Edwards

Reputation: 182

Pulling a hashed username from MySQL database

I'm working on a project where both the username and password need to be hashed with Argon2. I'm not having any trouble hashing them both in the registration and inserting them into the database, but I'm unable to pull the information for the login. Here is my login script:

<?php  session_start(); ?>
<?php
include 'config.php';
if(isset($_POST['submit'])){
$submittedUser = $_POST['username'];
$submittedPass = $_POST['password'];
$encrypteduser = password_hash($submittedUser, PASSWORD_ARGON2I);

$con=mysqli_connect($servername, $dbusername, $dbpassword, $dbname);
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
if ($stmt = mysqli_prepare($con, "SELECT * FROM users Where username =?")) {
                    mysqli_stmt_bind_param($stmt, "s", $encrypteduser);
                    mysqli_stmt_execute($stmt);
                    $result = mysqli_stmt_get_result($stmt);
}

while($row = mysqli_fetch_array($result))
{
$username = $row['username'];
$password = $row['password'];
}
if (password_verify($submittedUser, $username) && password_verify($submittedPass, $password))
{
$_SESSION['user']=$username; 

echo "<script> location.href='index.php'; </script>";
        exit;   
}
else
{
 echo "<script> location.href='login.php'; </script>";
        exit;   
}
mysqli_close($con);
}
?>

My current theory is that the hash being generated and stored in $encrypteduser does not match the one in the database. That would explain why no result is being pulled. Is there a way to get around this?

Upvotes: 1

Views: 493

Answers (2)

&#193;lvaro Gonz&#225;lez
&#193;lvaro Gonz&#225;lez

Reputation: 146530

What you want to do cannot be done because having the username stored in clear is exactly what allows to you determine what exact credentials (i.e. table row) you need to validate against.

Imagine you tried anyway. You want to validate john.doe. You would have to loop on every stored username hash, grab the corresponding salt so you can calculate the hash with john.doe and current row salt and then compare both username hashes. If there's no match, go to next row... until you eventually get a match and can finally determine what password hash to check. All this, with al algorithm specifically designed to be slow. Go figure.

Upvotes: 0

Alex Howansky
Alex Howansky

Reputation: 53581

This does not encrypt, it hashes:

$encrypteduser = password_hash($submittedUser, PASSWORD_ARGON2I);

I.e., it's one way. You (theoretically) can never get the original text back from it. It will also generate a different result every time you run it. As a result, you'll never be able to run a query with a WHERE clause to pick out one matching user. Rather, you'd have to iterate over every user in the system, running password_verify() against each of them.

So... don't do that. Leave the username in plain text so that you can benefit from the database index.

Upvotes: 2

Related Questions