How to retract a salted password from the Database and auth user?
Asked Answered
T

1

1

This is my first trial for implementing a member site with salted passwords which are all stored in the DB (MySQL). Everything works except for the error in the 'login for members' page.

The Error: Member login page accepts any entry to the membership site and for some reason passes my check for $result === false

This is the code for checking if member exists, please let me know what the problem is:

$servername = 'localhost';
$username = 'root';
$pwd = '';
$dbname = 'lp001';

$connect = new mysqli($servername,$username,$pwd,$dbname);

if ($connect->connect_error){
    die('connection failed, reason: '.$connect->connect_error);
}


$name = mysqli_real_escape_string($connect, $_POST['name']);
$password = mysqli_real_escape_string($connect, $_POST['password']);
$saltQuery = "SELECT salt FROM users WHERE name = '$name';";
$result = mysqli_query($connect, $saltQuery);
if ($result === false){
    die(mysqli_error());
}
$row = mysqli_fetch_assoc($result);
$salt = $row['salt'];

$saltedPW = $password.$salt;
$hashedPW = hash('sha256', $saltedPW);
$sqlQuery = "SELECT * FROM users WHERE name = '$name' AND password = '$hashedPW'";

if (mysqli_query($connect, $sqlQuery)){
    echo '<h1>Welcome to the member site '.$name.'</h1>';
}else{
    echo 'error adding the query: '.$sql_q.'<br> Reason: '.mysqli_error($connect);
}
Twitter answered 11/7, 2016 at 6:14 Comment(3)
See this it is almost turnkey for you, the login section, with password_verify() here: stackoverflow.com/a/33665819 . It includes session, error reporting, and try/catchNonresident
The SHA-* algorithms are not safe to store passwords, instead use the function password_hash() to generate a safe BCrypt hash. It will make it unnessecary to store the salt separately, have a look at this answer.Manchester
@Manchester - thank you, if you can write it up as code i'll put it as answer that would help me and others in the future, thx again bud.Twitter
M
2

Often developers struggle with the verification of a login password, because they are not sure how to handle the stored password hash. They know that the password should be hashed with an appropriate function like password_hash(), and store them in a varchar(255) field:

// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_DEFAULT);

In the login form, we cannot verify the password directly with SQL, nor can we search for it, because the stored hashes are salted. Instead we...

  1. have to read the password-hash from the database, searching by the user id
  2. and afterwards can check the login password against the found hash with the password_verify() function.

Below you can find some example code, showing how to do password verification with an mysqli connection. The code has no error checking to make it readable:

/**
 * mysqli example for a login with a stored password-hash
 */
$mysqli = new mysqli($dbHost, $dbUser, $dbPassword, $dbName);
$mysqli->set_charset('utf8');

// Find the stored password hash in the db, searching by username
$sql = 'SELECT password FROM users WHERE username = ?';
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('s', $_POST['username']); // it is safe to pass the user input unescaped
$stmt->execute();

// If this user exists, fetch the password-hash and check it
$isPasswordCorrect = false;
$stmt->bind_result($hashFromDb);
if ($stmt->fetch() === true)
{
  // Check whether the entered password matches the stored hash.
  // The salt and the cost factor will be extracted from $hashFromDb.
  $isPasswordCorrect = password_verify($_POST['password'], $hashFromDb);
}

Note that the example uses prepared statements to avoid SQL-injection, escaping is not necessary in this case. An equivalent example to read from a pdo connection could look like this:

/**
 * pdo example for a login with a stored password-hash
 */
$dsn = "mysql:host=$dbHost;dbname=$dbName;charset=utf8";
$pdo = new PDO($dsn, $dbUser, $dbPassword);

// Find the stored password hash in the db, searching by username
$sql = 'SELECT password FROM users WHERE username = ?';
$stmt = $pdo->prepare($sql);
$stmt->bindValue(1, $_POST['username'], PDO::PARAM_STR); // it is safe to pass the user input unescaped
$stmt->execute();

// If this user exists, fetch the password hash and check it
$isPasswordCorrect = false;
if (($row = $stmt->fetch(PDO::FETCH_ASSOC)) !== false)
{
  $hashFromDb = $row['password'];

  // Check whether the entered password matches the stored hash.
  // The salt and the cost factor will be extracted from $hashFromDb.
  $isPasswordCorrect = password_verify($_POST['password'], $hashFromDb);
}
Manchester answered 17/7, 2016 at 15:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.