【问题标题】:Salting passwords PHP, MySQL盐渍密码 PHP, MySQL
【发布时间】:2011-08-07 11:36:06
【问题描述】:

以下是加盐密码的好方法吗?

hash('sha256', $_POST['password'], $_POST['email'])

我将用户电子邮件用作盐。有些人不使用电子邮件,有些人说要使用随机数。

即使我使用随机数,我仍然需要将它存储在我的 MySQL 表中,所以盐仍然是已知的,并且使用电子邮件的额外好处是彩虹表的可能性大大降低,即使我要使用 16 位整数?

【问题讨论】:

  • 另请注意,这不会像您期望的那样工作。 hash() 的第三个参数是一个布尔值,表示原始输出。使用. 将电子邮件附加到原始密码,或将函数名称更改为hash_hmac(这是我的建议)...
  • 你是什么意思?我完全不明白,哈哈:p
  • 您将盐作为第三个参数传递给hash。该参数不适用于盐。相反,可以使用hash_hmac 函数(该函数设计用于在散列时以安全的方式组合两个字符串)。要了解我的意思,请尝试比较 hash('sha256', 'foo', 'bar');hash('sha256', 'foo') 的输出。它们应该是一样的。

标签: php mysql security


【解决方案1】:

盐背后的想法是防止黑客使用彩虹表。例如,如果黑客能够破坏您的数据库并找出散列密码是什么,他就不能轻松地对散列进行逆向工程以找到会生成相同散列的值。

但是,存在已散列的单词表,称为彩虹表。有些人已经费尽心思计算字典中每个单词的哈希值和其他常用密码。如果黑客拥有这些表之一,加上您数据库中的散列密码,就很容易找出密码是什么。

但是,盐改变了这一切,因为现在,您不是对密码进行哈希处理,而是对密码加上一些随机值进行哈希处理,这意味着彩虹表现在没用了。黑客是否可以破坏盐并不重要。

以明文形式保存盐是完全可以的。您想使用并非在所有用户中都统一的东西,因为这再次违背了目的。我个人喜欢使用创建帐户的时间戳。

这有意义吗?

【讨论】:

  • 是的,谢谢,所以如果我用时间戳加盐,将时间戳保存在数据库中,然后进行比较?
  • 我已经做到了。我使用预设(大)值对密码进行哈希处理,然后再次使用帐户创建的时间戳。
  • @Basic,你想使用 sha256。使用可以解密的加密算法您一无所获。事实上,你引入弱点并没有任何好处,因为如果有人泄露了你的密钥,他们就可以访问你的所有密码。但是,sha256 可确保即使您的数据库遭到破坏,用户的密码也不会泄露。
  • @Christian 因为攻击者可以简单地使用该盐重新创建彩虹表。这将是耗时的,但并非不可能。使用不同的盐需要为每个哈希使用不同的彩虹表,这对于攻击者来说要破解数据库中的每个密码将非常困难并且非常耗时。
  • 确保您定期备份您的数据库,并定期对备份的数据进行验证和有效性检查(不要只是备份并忘记它)。如果您使用像注册日期这样的数据库存储的盐,这是一个很好的策略,只需确保您不会为所有用户丢失它。 :)
【解决方案2】:

如果用户更改了他的电子邮件地址会怎样?您将无法再验证他/她的密码,因为盐值将消失。

您不应使用任何可能随时间变化的盐。生成一个随机盐(足够长以击败彩虹表)并将其与密码一起使用以生成哈希。

【讨论】:

  • 如果用户更改了他的电子邮件,那么当我插入新的电子邮件时,我会执行与创建帐户相同的操作。
  • 怎么样?您是否存储了纯文本密码以重新计算哈希?
  • 用户更改她的电子邮件地址将她拒之门外是完全正确的。但是,使用系统范围的 salt 的弹性不如每个用户的 salt。使用(仅)系统范围的盐,我只需要计算一个彩虹表。最好使用每个用户的随机盐,并强制我一次暴力破解密码。
  • 嗯,没想到,那样就不行了。感谢您的意见,您是否建议使用随机数并将其存储在数据库中?我已经读到您应该为每个帐户使用特定于用户的盐,而不是只使用一种盐。
  • 永远不要定义盐并在整个应用程序中使用它——它违背了拥有盐的目的。每个密码的盐必须是唯一的。
【解决方案3】:

目前,在 PHP 中使用密码散列的最佳解决方案是使用 bcrypt (blowfish) 实现。为什么?有几个原因:

  • 可变“工作”参数
  • 内置盐

请记住,如果您运行的不是 php 5.3,那么 crypt_blowfish 可能在您的系统上不可用。

工作参数

Blowfish/crypt 的设置时间已经很昂贵,但通过设置工作因子,您可以增加计算哈希所需的时间。此外,随着计算机变得更快并且能够更轻松地计算散列,您可以在未来轻松更改该工作因子。这使得特定的散列方法可以扩展。

内置盐

对我来说这只是懒惰,但我喜欢将盐和通行证存储在一起。

实施

要使用河豚,您需要按如下方式创建哈希

// salts must be 22 characters
$salt = "ejv8f0w34903mfsklviwos";

// work factor: 04-31 (string), each increase doubles the processing time.
// 12 takes my current home computer about .3 sec to hash a short string
$work = '12';

// $2a$ tells php to use blowfish
// you end up with a string like '$2a$12$mysalthere22charslong'
$options = '$2a$' . $work . '$' . $salt;

$hashedPass = crypt($plaintext, $options);

验证散列密码很简单:

if(crypt($user_input, $stored_password) == $stored_password) { echo "valid!"; }

现在,如果您想在任何给定时间增加工作系数,您可以在成功登录后获取提交的通行证,然后重新散列并保存它。由于工作因素与盐和密码一起保存,因此更改对系统的其余部分是透明的。

编辑

在 cmets 中似乎存在一些混淆,认为河豚是一种双向加密密码。它在 crypt 中没有这样实现。 bcrypt 是一种自适应密码散列算法,它使用 Blowfish 密钥调度,而不是对称加密算法。

您可以在这里阅读所有相关信息:http://www.usenix.org/events/usenix99/provos.html

或者您可以在此处阅读更多关于使用 bcrypt(河豚的哈希实现)的信息:http://codahale.com/how-to-safely-store-a-password/

【讨论】:

  • 每个人都在说使用 bcrpyt,我想我会的,因为如果它导致过载,你可以更改 $work,反之亦然:) 谢谢
  • Blowfish 是一种密码,而不是散列算法。 MD5 是一种散列算法。
  • 密码散列方法使用 crypt 使用从 Blowfish 派生的算法,该算法利用了慢速密钥调度
  • 克里斯蒂安,你错了。使用此方法散列的密码具有破坏性,无法通过暴力破解以外的任何方式恢复。事实上,OpenBSD 也使用了同样的方法
  • @christian。在继续此论点之前,您可能需要阅读。最后一次:bbcrypt 是一种自适应密码散列算法,它使用 Blowfish 密钥调度,而不是对称加密算法。是的,河豚是一种密码。你是对的。 Bcrypt 不是。我将其称为“河豚”只是因为 PHP 在他们的文档中将其称为“CRYPT_BLOWFISH”。加密算法不是河豚
【解决方案4】:

我建议使用如下迭代。 crypt 可以替换为 md5 或任何其他散列算法。 10 可以是任意数字。

$pass=mysql_real_escape_string($_POST['pass']);

$iterations = 10;
$hash = crypt($pass,$salt);
for ($i = 0; $i < $iterations; ++$i)
{
  $password = crypt($hash . $pass,$salt);
}

此外,您可以添加任何其他变量。我希望这能解决问题

【讨论】:

    【解决方案5】:

    你可以用这个:

    $salt='whatever';
    $a=hash('sha256', $_POST['password'], $salt);
    $b=hash('sha256', $_POST['email'], $salt);
    $hash=$a.'-'.$b;
    

    当用户更改电子邮件时,只需执行以下操作:

    $old_a=substr($old_hash,0,strpos($old_hash,'-'));
    $new_b=hash('sha256', $_POST['email'], $salt);
    $new_hash=$old_a.'-'.$new_b;
    

    【讨论】:

    • 你不喜欢那些争论失败的人大肆投票吗?
    • 好吧,“随便”的盐不是随机的,所以至少是错误的。并且没有解释为什么您与通常做法相反,选择将电子邮件地址添加到哈希中。
    • @Jacco - [1] 我认为任何对加盐的概念了解一半的人都会替换盐,即使它不是“随便”而是随机的东西。理想情况下,攻击者不应该知道盐。顺便说一句,与我输入的随机内容相比,用户更有可能替换“随便”。哦,顺便说一句,“随便”是一种足够好的盐。没有一个头脑清醒的人会蛮力强迫盐。 [2] 由于 OP 想在哈希中添加一封电子邮件,我以一种可用的方式为他做了。 [3] 仅仅因为我不遵循货物狂热的编程,并不意味着我错了。
    • 根据定义,盐是随机的。如果它不是随机的,我们称之为密钥。不,恒定值不是足够好的盐。关于盐的更详细的文章:stackoverflow.com/questions/1645161/… 另外,我并不是说您偏离常见的最佳实践是错误的,但您至少应该解释为什么这样做。没有必要提及货物崇拜编程,这意味着我不知道评论背后的“原因”,或多或少地取消了任何进一步讨论的资格。
    • @Jacco - 我真的需要重新审视我的理由吗? [1] 在这种情况下,您失去了随机的含义。随机意味着攻击者不容易猜到的东西。无论如何考虑到长度很小,“随便”都不是好盐,但也不是“不是盐”。 [2] 你应该费心阅读 OP 的问题,而不是诉诸这样的论点,如果有人不理解上下文,我应该受到责备吗?
    猜你喜欢
    • 2014-10-31
    • 2011-04-03
    • 1970-01-01
    • 2016-07-28
    • 2021-10-02
    • 2011-06-25
    • 1970-01-01
    相关资源
    最近更新 更多