【问题标题】:Is this a safe way to store my passwords?这是存储密码的安全方式吗?
【发布时间】:2011-11-04 05:42:11
【问题描述】:

我一直在阅读有关此主题的一些不同指南/教程,发现以下内容:

我知道我所阅读的内容是一种非常安全的方式来存储用户密码。我尝试将 2 稍微组合起来,而不是像第一个示例中那样使用 mt_rand,而是生成了自己的动态盐。

这是我的代码:

<?php

    $static_salt = ""; // Removed value for obvious reasons

    $dynamic_salt_choice = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    $dynamic_salt_length = 40;

    $dynamic_salt = "";

    $dynamic_salt_max = strlen($dynamic_salt_choice)-1;

    for ($i = 0; $i < $dynamic_salt_length; $i++) {

        $dynamic_salt .= substr($dynamic_salt_choice, rand(0, $dynamic_salt_max), 1);

    }

    $password_length = length($password);
    $split_at = $password_length / 2;
    $password_array = str_split($password, $split_at);

    $password = $password_array[0] . $static_salt . $password_array[1];

    $password_hash = hash_hmac('sha512', $password, $dynamic_salt);

?>

据我说,这是获取静态盐,生成动态盐,然后我们将给定密码分成数组中的两部分,并在两个密码部分之间添加静态盐。

然后我们使用sha12 以及动态盐对密码进行哈希处理。

我的问题是,这比我链接到的 2 种方法更安全还是一样安全?还是我通过这种方式混淆了它使其更容易受到攻击?

我还认为它在 cookie 中存储 $password_hash 旁边的用户名 cookie 用于自动登录是一个很大的禁忌吗?如果是这样,网站如何通过 cookie 以安全的方式记住您?

【问题讨论】:

标签: php security encryption hash passwords


【解决方案1】:

我正在尝试提高我的网站的安全级别

好吧,让您知道,没有密码哈希ussue可以提高您的网站安全性。
您必须关注其他更重要的事情,例如 SQL 和文件注入、XSS 和 CSRF 漏洞。 如果您确保您的网站安全,它会保护您的密码以及安全,就像副作用一样。

接下来您必须关注的是密码强度没有哈希可以保护愚蠢的密码,例如 joe123

至于散列本身 - 你可以使用任何你想要的东西,一些基本的东西,比如使用一些理智的盐,比如注册时间或电子邮件,以及任何散列函数的一些迭代就足够了。不要在散列中赋予太多意义。它不像发明一些额外安全的原始算法那样需要如此多的关注。

我的问题是,这比我链接到的 2 种方法更安全还是一样安全?还是我通过这种方式混淆了它使其更容易受到攻击?

不知道你是否相信我(我打赌你不会),但所有这些方法都足够安全,不需要改进。并且不会影响网站的安全性,而只会影响密码本身以防万一他们利用您网站中的另一个漏洞被盗

我还认为将 $password_hash 存储在 cookie 中以及用于自动登录的用户名 cookie 是一个很大的禁忌?

我不认为公开哈希本身是明智之举。但同样,它不会影响站点安全,只会影响密码潜在漏洞。如果您的哈希值和密码足够强大,那么逻辑让我说它足够安全。

【讨论】:

  • 我也尽我所能防止 SQL 注入等(我会去改写那部分) - 但是如果他们正在阅读,感谢你为其他人指出这一点。因此,“这是最好的方法”并不确定——只要使用动态和静态的盐,你就可以开始了吗? cookie的情况呢?
  • 重点不在于 SQL 注入,而在于密码散列不会影响您的站点安全。
【解决方案2】:

假设$dynamic_salt 与最终的$password_hash 一起存储——因为没有它,哈希就无法测试——这个方案非常弱。使用盐确实可以防止彩虹表,但非迭代的 HMAC 使该方案无法抵御暴力攻击。 (盐的长度对你没有好处,因为它是哈希输入中的一个已知常数。把它放在原始密码的中间也没有真正的帮助。)

总的来说,这个方案远弱于bcrypt(),因为它只(有效地)迭代哈希两次。如果你只是使用更简单的方案存储密码,你真的没有更好的办法,例如:

$salt = uniqid();
$password_hash = hash_hmac('sha512', $password, $salt);

但您最好还是使用别人的(经过验证的)密码加密例程,而不是自己动手。


关于在 cookie 中使用密码哈希 - 这是要避免的,因为它允许攻击者对数据库具有只读访问权限(例如,通过 SQL 注入攻击或被盗的备份)在不知道或更改密码的情况下冒充您的应用程序中的任何用户。这也意味着,如果用户的计算机已设置为自动登录,则密码哈希将存储在其上。我会避免这种情况。

更好的方案可能是在用户选择自动登录时在 cookie 中设置随机生成的随机数,然后将该随机数的哈希值存储在数据库中。这样,服务器就可以检查登录密钥的正确性,而无需“记住”它。

【讨论】:

  • 感谢您的回复,我很可能会坚持使用经过测试的方法。至于cookie的情况,我有点困惑。肯定将会话令牌存储在用户计算机上,并将其链接到帐户仍然很危险,因为这可能会被伪造/猜测/被盗等?这是一种安全的方法吗?
  • 任何让用户登录的方案都将涉及,在某些时候,将 something 存储在与其帐户相关联的用户计算机上——这是不可避免的。这里重要的是,您存储的内容不是他们帐户的关键部分(例如密码哈希),并且无法从您直接存储在数据库中的任何数据中推导出来。
【解决方案3】:

这似乎是一个合理的腌制方案,尽管可能有点矫枉过正。它可能不需要 40 个字符长 - 你只是想炸毁彩虹桌的大小,而不是做一个无法猜测的随机数 - 但让它长不会有坏处。

对于自动登录,您应该(在 cookie 中)存储一个随机令牌,该令牌对应于指向用户帐户的数据库条目。当用户更改密码时,删除该用户的所有这些条目。生成此令牌时,rand() 不够好 - 您需要一个安全不可猜测的随机数。不幸的是,PHP 并没有真正内置用于安全随机数的工具——mt_rand() 已经接近了它,但我个人会在 Linux 系统上直接从/dev/urandom 读取随机字节并使用它来生成我的随机数。

【讨论】:

    【解决方案4】:

    可以使用盐,但它有其自身的局限性。另一种方法是使用 bcrypt。更多信息可以在http://www.openwall.com/phpass/ 找到

    我认为这篇 SO 文章绰绰有余Secure hash and salt for PHP passwords

    【讨论】:

    • 那是我链接到的同一篇 SO 文章,我的问题仍然存在......我的方式比那里和/或我链接到的其他文章上发布的内容更安全吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-03
    • 1970-01-01
    • 2013-05-03
    相关资源
    最近更新 更多