如何从数据库和身份验证用户中撤回加盐密码?

2022-01-21 00:00:00 passwords salt membership php mysql

这是我第一次尝试使用全部存储在数据库 (MySQL) 中的加盐密码来实现会员网站.除了会员登录"页面中的错误之外,一切正常.

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.

错误:会员登录页面接受会员网站的任何条目,并且由于某种原因通过了我对 $result === false

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

推荐答案

开发人员经常在验证登录密码时遇到困难,因为他们不确定如何处理存储的密码哈希.他们知道应该使用适当的函数对密码进行哈希处理,例如 password_hash(),并将它们存储在 varchar(255) 字段中:

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

在登录表单中,我们无法直接用 SQL 验证密码,也无法搜索,因为存储的哈希是加盐的.相反,我们...

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. 必须从数据库中读取密码哈希,通过用户 ID 进行搜索
  2. 然后可以使用 对照找到的哈希检查登录密码password_verify() 函数.

您可以在下面找到一些示例代码,展示如何使用 mysqli 连接进行密码验证.该代码没有错误检查以使其可读:

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

请注意,该示例使用准备好的语句来避免 SQL 注入,在这种情况下不需要转义.从 pdo 连接读取的等效示例如下所示:

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

相关文章