【问题标题】:How to hash multiple passwords at once, efficiently?如何有效地一次散列多个密码?
【发布时间】:2015-04-25 14:15:26
【问题描述】:

我有一个 mysql 表,其中包含 userid、password、hashedpassword 列。我曾经将密码作为纯文本存储在密码列中。我现在意识到这是不可接受的,并且现在想对所有这些进行散列并将它们以正确的方式存储在 hashedpassword 字段中。

你会对下面的脚本生气,因为它的效率低得可怕。正如您可能猜到的那样,它在我的服务器上超时。有人可以帮助一个明显缺乏经验的程序员以正确的方式更新数据库中的所有这些字段吗?清楚地为每条记录连接到数据库是愚蠢的:(...

$sql = "SELECT * 
        FROM users";
            $result = mysqli_query($connection, $sql);
            if (!$result) {
            die("Database query failed: " . mysqli_error($connection));
            } else {
                while ($row=mysqli_fetch_array($result)) {
                    $userid=$row['userid'];
                    $passwordhashed=password_hash($row['password'], PASSWORD_DEFAULT);
                    $sql = "UPDATE users
                        SET hashedpassword='$passwordhashed'
                        WHERE userid='$userid'
                        LIMIT 1";
                            $update = mysqli_query($connection, $sql);
                            if (!$update) {
                            die("Database query failed: " . mysqli_error($connection));
                            } else {
                                //we good
                            }

                }

            }

【问题讨论】:

  • 为什么必须同时出现?您可以分别执行多个更新,我认为它会更有效。有什么理由应该马上?
  • 很可能这只是一次性的事情,所以只需用他们的密码、哈希和每一个循环用户,然后创建一个 sql 字符串或一个文件,然后在终端中执行它
  • 它是一次性工作,不管需要多长时间
  • “为每个记录清楚地连接到数据库是愚蠢的”你不这样做,你做一个选择然后每个用户更新一次,所有这些都使用一个连接。这是正确的
  • 不要通过网络服务器运行长时间运行的作业!通过 SSH 或其他方式登录您的服务器,然后在命令行上运行 $ php update_all_passwords.php。那里没有超时(通常)。如果您不知道我刚刚写的任何内容是什么意思,那么是时候弄清楚了。 :o)

标签: php mysql sql hash


【解决方案1】:

出于好奇,您的表中有多少用户行?

我在不久前升级到password_hash 函数时使用了一个系统(来自 - 类似地 - 不明智的纯文本存储),我使用这种散列方法制作了一个脚本来用新密码更新密码。

不同之处在于部署 - 我向所有客户 (~1600) 发送了电子邮件,并告诉他们单击电子邮件中的链接以更新他们的密码以防万一,输入他们当前的密码和一个新的(不同的)密码,因此每个密码都是单独更新 AND 纯文本密码不用作散列密码,如果有人已经拥有您的表格副本并且可以查找纯文本密码,则只需转换它们散列不会锁定那扇门,相反他们仍然可以进入并在用户帐户上乱七八糟。

(如果你认为“哦,没关系,没有人会拥有我的表格的副本”,这种思维逻辑也意味着你不需要首先加密你的纯文本密码! -- MySQL 可以被黑客入侵,如果黑客小心谨慎,而不是炫耀他们的垃圾邮件黑客技能,那么您不必知道这一点)

这也意味着只有未遵循电子邮件建议的客户才会面临当前或未来违规的风险。我还在站点登录中包含了类似的转换代码,在此过程中强制选择新密码。

【讨论】:

    【解决方案2】:

    您的总体策略是正确的。如果您遇到超时问题,那可能不是代码问题,而是您的运行方式问题。

    是否可以通过命令行运行此脚本?这不像 Web 请求那样具有内在的超时。通常,您以这种方式执行长时间运行的迁移脚本,因为预计它们会比通常的页面渲染花费更长的时间。

    要考虑的另一件事是创建一个prepared statement,然后多次执行。准备好的语句用作查询的模板,并且当正确绑定和执行时,每次都可以对不同的记录进行操作。这通常比为每个查询发送不同的语句要快。

    password_hash 函数故意变慢。在成千上万的用户上运行此程序将花费大量时间,这是无法解决的。它比 MD5 等安全得多的原因在于散列的计算成本。

    值得注意的是,您的UPDATE 中的LIMIT 1 应该是不必要的,因为您将其范围限定为userid,其中应该具有UNIQUE 约束。

    我会补充一点,如果你想正确地这样做,你会使用development framework 比如Laravel,因为其中大多数都带有某种authentication system 内置的。我敢肯定你已经开始发现,自己动手是非常冒险的。

    【讨论】:

      猜你喜欢
      • 2018-01-28
      • 2015-06-29
      • 1970-01-01
      • 2011-09-14
      • 1970-01-01
      • 1970-01-01
      • 2019-12-12
      • 2011-05-10
      • 1970-01-01
      相关资源
      最近更新 更多