【问题标题】:How to hash and salt passwords如何散列和加盐密码
【发布时间】:2011-06-02 11:33:26
【问题描述】:

我意识到这个话题有时会被提起,但我发现自己还不能完全确定这个话题。

我想知道您如何对哈希进行加盐并使用加盐的哈希?如果密码是用随机生成的盐加密的,当用户尝试进行身份验证时,我们如何验证它?我们还需要将生成的哈希存储在我们的数据库中吗?

有没有什么特定的方法可以生成盐?倾向于使用哪种加密方法?据我所知,sha256 还不错。

当用户进行身份验证时,将哈希“重新加盐”是否是一个想法?最后,重复多次是否有任何重大的安全性提升?

谢谢!

【问题讨论】:

标签: php security encryption hash


【解决方案1】:

答案是不要自己做。使用 bcrypt 可以满足您在 PHP 中的所有需求。

阅读这篇文章,它很容易理解并解释你所问的一切:http://codahale.com/how-to-safely-store-a-password/

bcrypt 会自行考虑散列,并且可以根据需要将其配置为“复杂”,以在被黑客入侵时保持用户密码的完整性。

哦,我们不“加密”密码,我们散列它们。

【讨论】:

  • 那篇文章有一个谎言。 bccrypt 对字典攻击没有帮助。无盐 bccrypt 很容易受到彩虹的影响。
  • 并非如此。您需要为每个 bcrypt 配置生成不同的彩虹表。为 bcrypt 生成彩虹比为标准哈希生成彩虹要复杂数百万倍。
  • 不过,彩虹桌是一次完成,可以永远使用的东西。所以,这是完全不使用盐的弱借口。您的文章作者只是另一个大嘴巴,他对某些方法嗤之以鼻,将另一种方法理想化。而事实是一起使用所有适当的方法。
  • 不,这不正确。您需要为您要攻击的每个不同站点创建一个彩虹表。这使得彩虹桌的整个想法毫无用处。
  • @Col。弹片:那篇文章中没有提到使用盐。事实上 bcrypt(和 phpass)使用盐,这些非常重要。
【解决方案2】:

您需要同时存储散列和用于计算散列的盐。

如果您想检查输入是否等于原始输入值,您可以使用相同的盐重新计算哈希,并将存储的哈希与新计算的哈希进行比较。如果它们相等,则两个输入值都是相同的(直到某个特定概率)。

哈希算法的选择也很重要。因为有快速散列算法和相当慢的散列算法。并且由于您想要很难找到冲突(至少在蛮力中),请使用较慢的散列算法。

【讨论】:

    【解决方案3】:

    我想知道你是怎么做到的 加盐哈希并使用加盐的 哈希?如果密码被加密 用随机生成的盐,怎么能 我们在用户尝试时验证它 进行身份验证?我们需要存储吗 我们数据库中生成的哈希为 好吗?

    是的。首先生成一个盐,然后从密码和盐生成一个哈希,并将哈希和盐保存在一起。

    盐有什么具体的方法吗 最好应该生成?

    我怀疑人们是否就更可取的做法达成了共识。我使用 /dev/random。例如

    $salt = '$2a$12$' 
        . strtr(substr(base64_encode(shell_exec(
            'dd if=/dev/random bs=16 count=1 2>/dev/null'
            )), 0, 22), '+', '.')
        . '$';
    $hash = crypt($input, $salt);
    

    青睐哪种加密方式 使用?据我所知,sha256 是 很好。

    请参阅 Computer Guru 的答案,即如上例所示使用 bcrypt。请参阅PHP manual page on crypt()。如果您的系统上没有 bcrypt,获取它的一种方法是 the Suhosin patch

    有哈希值是个好主意吗 当用户“重新腌制” 认证?

    盐只会让字典攻击变慢。如果你有一个不错的随机盐开始,我认为经常更换它不会有帮助。您最好投入精力让用户选择好的密码,经常更改密码并将 Blowfish 成本参数保持在合理的值。

    最后,它是否有任何主要的安全性 boost 可以重复很多次?

    这个问题属于密码设计领域。我建议你把它留给专家。换句话说:忘记它——只使用最佳的常见做法。

    【讨论】:

    • 安全专家提倡你应该rehash多次(数千次),这使得彩虹表的计算速度慢了数千倍。
    • 我的措辞不清楚,抱歉。我所说的“忘记它”并不是指忘记重新散列。我的意思是忘记尝试自己回答问题,而是遵循 BCP。而且,正如您所说,BCP 确实建议重新散列。但是,iiuc,仅当您使用 MD5 之类的快速散列函数之一或 SHA 之一时,在您自己的代码中重新散列数千次才是重要的。使用 bcrypt,成本参数控制使用多少次迭代。在我给出的示例中,成本因子为 12,在我的旧 iMac 上生成哈希需要 0.37 秒。
    【解决方案4】:

    你通常做的事情是这样的:

    salted = HASH(password . key); // DON'T DO IT LIKE THIS 
    

    其中 key 是“盐”——存储在配置文件中的密钥。因此,为了破解密码,您需要密钥和数据库,因此最好存储它们 在不同的地方。

    因为我展示的架构不够强大,所以最好使用 HMAC 来实现此目的,而不是手写加盐。这样的操作就像 hash 一样简单,PHP 支持。

    salted = hash_hmac('sha1',password,key); // <-- this is ok
    

    看到这个:http://php.net/manual/en/function.sha1.php

    【讨论】:

    • 使用密钥进行散列攻击。使用 HMAC 可能更好。
    【解决方案5】:

    三个简单的规则。好的,五个:

    1. 最重要的一点,如果您想确保您的密码存储是安全的:只允许使用强密码,例如至少 8 个字符,包括一些不同的大小写字母和数字,甚至标点符号
    2. 只允许用户使用强密码。制定例行检查长度和字符范围并拒绝弱密码。甚至为自己获取 John the ripper 数据库并对其进行检查。
    3. 恶意地折磨用户,殴打他们,直到他们选择足够长且随机的密码。密码!不是盐,每个人都乐于谈论几个小时,但密码本身应该足够随机!
    4. 为您的密码加盐并将加盐与用户信息一起存储。您可以使用用户电子邮件和用户名作为完美的盐,无需随意发明一些非凡的东西。
    5. 某些算法并不那么重要,您也可以使用 MD5。在现实世界中,很少有人会为破解您著名的钓鱼和杂货爱好者协会网站论坛的用户数据库而烦恼。

    【讨论】:

    • 使用电子邮件作为 salt 的一部分有点不稳定,因为用户可能会更改他们的电子邮件地址。加盐的重点是两个具有相同密码的用户不会有相同的哈希(它可以击败彩虹表攻击,或者更准确地说,每个用户记录需要一个单独的彩虹表)。一个强有力的方法是使用大量的熵(/dev/urandom,如果可以的话),存储 64 位随机数据​​作为用户记录的一部分,并将其用作盐。打败它的彩虹桌将是难以企及的。
    • @MightyE 你可能误解了彩虹表这个词。 “每个用户记录的彩虹表”称为“字典攻击”
    • 用户名和电子邮件地址如何用作盐?它们非常容易预测。
    • @GregS 是的。所以呢?什么是攻击场景?
    • 关于第 3 点 - 即使您的网站本身无趣,您的用户数据库 对攻击者也很有用,因为您有一半的用户可能在 gmail / 上使用相同的密码facebook / 其他有吸引力的网站。 (例如,请参阅最近的 Gawker 案例,该案例导致 Twitter 垃圾邮件来自受感染的帐户)。