【问题标题】:Comparing hashed password in query比较查询中的哈希密码
【发布时间】:2016-09-29 10:32:48
【问题描述】:

(PHP 和 MySQL 不是我的专业领域,所以这可能是一个简单的单行)。

我刚刚从互联网上获取了一段执行用户注册的代码。除其他外,它使用以下行对密码进行哈希处理:

$salt = dechex(mt_rand(0, 2147483647)) . dechex(mt_rand(0, 2147483647)); 
$password = hash('sha256', $_POST['password'] . $salt); 
for($round = 0; $round < 65536; $round++){ $password = hash('sha256', $password . $salt); }

如果我理解正确,它使用 SHA-256 将密码和盐值的哈希值存储在密码字段中。

现在我需要编写一个查询,当提供用户名和密码时,它会返回 UserID 值。阅读 MySQL 手册,似乎没有 SHA-256 的内置函数(支持旧的 SHA 和 MD5)。还是不是这样?

SELECT 
     id 
FROM 
     users 
WHERE 
     (username = @UN) 
     AND (password = SHA256(CONCAT(@PWD, salt)))

这显然行不通,因为未定义 SHA256。

编辑

刚刚发现 MySQL 5.5.5 中有 SHA2 可以做 SHA-256:

SELECT 
     id 
FROM  
     users 
WHERE 
     username = @UN 
     AND password = SHA2(CONCAT(@PWD, salt), 256)

但这也不会返回任何行。也许我并没有完全按照上面的注册页面所做的那样做。

编辑 2

我可能还不够清楚。我从 .NET 查询数据库,而不是 PHP。我包含的 PHP 代码最初只是为了展示它是如何存储的。这意味着我必须依赖 MySQL 的能力来做散列,或者在 .NET 中做,如果 MySQL 不能在查询中做的话。

编辑 3

我最终在第一步中针对用户名获取盐值,然后在 .NET 中以与上述 PHP 代码中完全相同的方式进行哈希处理,然后将其传递给 MySQL 以获取用户 ID。

【问题讨论】:

  • 为什么不先计算哈希并在查询中使用它?
  • 您“获取了一段代码”,却不知道它是如何处理安全存储密码的?这是非常不负责任的。
  • @SrinivasaReddy 什么?没有人会在用户表中保存盐。
  • @Justinas 你不知道加盐是干什么用的。将每个用户的 salt 存储在 users 表中就可以了。
  • @dotNET 安全的盐存储是您最不必担心的问题。使用真正的密码散列算法。 SHA 系列函数不适用于此目的。

标签: php mysql sql hash


【解决方案1】:

确认电子邮件和密码时,您通过电子邮件请求用户

SELECT * FROM users WHERE username = :username;

然后将数据库密码与传递的密码进行比较:

if ($db->password == $this->hash($_POST['password'])) {
    //Match
} else {
    //Does not match
}

或者您可以从 PHP 端将哈希传递给 MySql:

SELECT id FROM users WHERE username = :username AND password = :passwordHash

最好的是使用 PHP 函数 password_hash(),它会为你生成盐,并让密码类似于 $2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a
要验证密码,您只需拨打password_verify($_POST['password'], $dbPasswordHash)

More about passwords

【讨论】:

  • 也许我不够清楚。我从 .NET 访问数据库,而不是 PHP。我包含的 PHP 代码最初只是为了展示它是如何存储的,这意味着我必须依赖 MySQL 的能力来进行散列(或者可能在 .NET 中进行?)。
  • @dotNET 您将问题标记为 PHP 问题,甚至提到您使用 PHP,您甚至展示了 PHP 代码示例。你没有提到.NET...
【解决方案2】:

通常的例外做法是从您的应用程序代码中用户提供的密码生成一个哈希,然后将该哈希与存储在数据库中的那个进行检查。

另外,php 已经内置了处理这个问题的函数,而且它们几乎肯定会比一些自制的选项设计得更好,尤其是你在没有完全理解的情况下复制的选项。

最初保存密码:

$hashed = password_hash($_POST['password']);
DB::insert('users',['email'=>$email, 'password'=>$hashed]);

在登录时检查:

$user = DB::select('users',['email=?', $_POST['email']]);
if($user && password_verify($_POST['password'], $user['password'])){
   //good to go
}

http://php.net/manual/en/function.password-hash.php

http://php.net/manual/en/function.password-verify.php

根据您的评论进行编辑,如果您需要在 .NET 应用程序中更改密码,以下 SO 答案可能会有用:

looking for c# equivalent of php's password-verify()

【讨论】:

  • 谢谢。我最终在步骤 1 中针对用户名获取盐值,然后在 .NET 中以与上面 PHP 代码中完全相同的方式进行哈希处理,然后将其传递给 MySQL 以获取用户 ID。
猜你喜欢
  • 2023-03-29
  • 2016-09-13
  • 1970-01-01
  • 2022-01-24
  • 2017-03-01
  • 1970-01-01
  • 2019-11-11
  • 2020-11-13
  • 1970-01-01
相关资源
最近更新 更多