如何有效地一次散列多个密码?

时间:2015-02-24 03:25:08

标签: php mysql sql hash

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

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

$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
                            }

                }

            }

2 个答案:

答案 0 :(得分:0)

出于好奇,您在表中拥有多少行?

当我升级到password_hash函数(来自 - 类似 - 不明智的纯文本存储)时,我在我的系统上工作了一段时间,我创建了一个脚本来更新密码,使用这个散列方法

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

如果你认为"哦,没关系,没有人会有我的桌子的副本",这种思想逻辑也意味着你不会首先需要加密您的纯文本密码! - 如果黑客小心谨慎而不是有人炫耀他们的垃圾邮件技能,那么MySQL可能被黑客攻击而你无需了解它。

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

答案 1 :(得分:0)

这里的总体策略是正确的。如果您遇到超时问题,这可能不是代码问题,而是您如何运行它。

通过命令行运行此脚本是一个选项吗?这并不像Web请求那样具有固有的超时功能。通常,您以这种方式执行长时间运行的迁移脚本,因为它预计它们会比通常的页面呈现更长时间。

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

password_hash功能故意慢。在成千上万的用户上运行这将花费很多时间,没有办法解决这个问题。它比MD5更安全的原因是由于散列的计算成本。

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

我想补充一点,如果您想要正确使用{0} {} 就像development framework一样,因为大多数都带有某种Laravel内置版本。滚动你自己是非常冒险的,因为我确定你已经开始发现了。