如何对密码进行哈希和加盐处理

7
我知道这个话题已经被提出过很多次,但我仍然不确定这个话题。 我想知道如何给哈希加盐并使用已加盐的哈希? 如果密码使用随机生成的盐进行加密,当用户尝试认证时,我们如何验证它? 我们需要在数据库中存储生成的哈希吗?
盐应该有特定的生成方式吗? 哪种加密方法最好使用? 据我所听,sha256非常好。
当用户进行身份验证时,将哈希“重新加盐”是否是一个好主意? 最后,重复哈希会有任何重大安全提升吗?
谢谢!

说到安全性提升 - 检查您的网站是否存在 SQL 或文件注入。修复它们后,再处理 XSS 注入。 - Your Common Sense
如何使用 PHP 5.5 密码哈希函数 - Sliq
还可以查看Openwall的Portable PHP密码哈希框架(PHPass)。它经过加固,能够抵御许多常见的用户密码攻击。 - jww
5个回答

7
答案是不要自己尝试。在PHP中,可以使用bcrypt一行代码来完成你需要的所有操作。
阅读这篇文章,它易于理解并解释了你提出的所有问题:http://codahale.com/how-to-safely-store-a-password/ bcrypt本身考虑到了哈希处理,并可以配置为“复杂”程度,以保持用户密码的完整性,即使被黑客攻击也能保证安全。
哦,我们不是“加密”密码,而是对其进行哈希处理。

3
这篇文章有一个谎言。Bccrypt在面对字典攻击时是无效的。未加盐的Bccrypt易受彩虹表攻击。 - Your Common Sense
2
然而,彩虹表是一种只需完成一次就可以永久使用的工具。因此,这并不是完全不使用盐的一个充分理由。你的文章作者只是又一个喜欢诋毁某些方法并理想化其他方法的人。事实上,真正有效的方法是将所有适当的方法结合起来使用。 - Your Common Sense
是的。如果您没有使用像bcrypt或pbkdf等东西,盐对您没有帮助。我不明白这个问题有什么难以理解的,Col Shrapnel。 - Mahmoud Al-Qudsi
@Shrapnel上校:bcrypt的规范包括盐。不存在“未加盐的bcrypt”。它确实有助于防止离线字典攻击,通过显著增加每个密码测试所需的工作因素(当然,如果您的密码是“password”或“12345”,那么它对您没有帮助,但没有什么会有帮助)。 - caf
嗨, 我刚刚发现了一篇关于这个主题的有趣文章。我认为它可能会有所帮助:http://crackstation.net/hashing-security.htm - Krzysztof Lenda
显示剩余6条评论

2
你需要存储计算哈希值所使用的哈希和盐。
如果你想检查一个输入是否等同于原始输入值,你可以使用相同的盐重新计算哈希值,并将存储的哈希值与新计算的哈希值进行比较。如果它们相等,则两个输入值是相同的(至少在某个特定概率上)。
哈希算法的选择也很重要。因为有快速哈希算法和相对较慢的哈希算法。而且,如果你想使碰撞难以被发现(至少在暴力破解中),请使用较慢的哈希算法。

1

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

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

其中key是“盐” - 存储在配置文件中的秘密密钥。因此,为了破解密码,您需要同时拥有秘密密钥和数据库,因此最好将它们存储在不同的位置。

由于我展示的模式不够强大,所以最好使用HMAC来代替手写的加盐。这样的操作就像哈希一样简单,而且PHP也支持这种操作。

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

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


哈希加密中存在针对密钥的攻击。使用HMAC可能更好。 - jww

1
我想知道如何对哈希值进行加盐并使用加盐的哈希值?如果密码是使用随机生成的盐进行加密,那么当用户尝试认证时我们如何验证它?我们需要在数据库中存储生成的哈希值吗?
是的。首先,您需要生成一个盐,然后从密码加上盐生成哈希值,将哈希值和盐一起保存。
盐应该如何生成?我不确定是否有共识。我使用 /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还不错。
请参考计算机大师的答案,即像上面的示例一样使用bcrypt。请参阅PHP手册页面上的crypt()。如果您的系统上没有bcrypt,则可以通过Suhosin补丁来获取它。
当用户进行身份验证时,“重新加盐”哈希值是否是一个好主意?
盐只是使字典攻击变慢的一种方式。如果您有一个足够随机的盐,我认为经常更改它并不会有所帮助。您最好投入精力让用户选择好密码,定期更改密码,并将您的Blowfish成本参数保持在合理的值。
最后,多次重新哈希它是否会有任何重大安全提升?
这个问题属于密码设计领域。我建议您把它留给专家。换句话说:忘掉它——只需使用最佳常规实践即可。

安全专家建议您应该重新散列多次(数千次),这使得彩虹表的计算变得缓慢数千倍。 - Alix Axel
我的措辞不清楚,很抱歉。当我说“忘了它”时,我并不是指放弃重新散列。我是指忘记试图自己回答问题,转而遵循最佳实践。正如你所说,最佳实践确实推荐重新散列。但是,如果您使用其中一个快速哈希函数(如MD5或其中一种SHA),则在您自己的代码中进行数千次重新散列非常重要。对于bcrypt,成本参数控制使用多少次迭代。在我给出的示例中,成本因素为12,散列需要0.37秒才能在我的旧iMac上生成。 - user213154

0

三个简单的规则。好吧,其实是五个:

  1. 最重要的事情,如果你想让你的密码存储安全:只允许使用强密码,例如至少8个字符,包含大小写字母、数字和标点符号。
  2. 只允许用户使用强密码。制定一个例行程序来检查长度和字符范围,并拒绝弱密码。甚至可以获取John the ripper数据库并进行检查。
  3. 狠狠地折磨用户,逼迫他们选择足够长且随机的好密码。密码!不是盐,每个人都喜欢花费数小时来谈论它,但密码本身应该足够随机!
  4. 给你的密码加盐,并将盐与用户信息一起存储。你可以使用用户的电子邮件和用户名作为完美的盐,无需发明什么非常随机的东西。
  5. 特定的算法并不那么重要,你也可以使用MD5。在现实世界中,很少有人会费心去破解你著名的“钓鱼和杂货粉丝协会”网站论坛的用户数据库。

1
使用电子邮件作为盐的一部分有点不稳定,因为用户可能会更改他们的电子邮件地址。盐的重点在于,具有相同密码的两个用户将不会具有相同的哈希值(这会破坏彩虹表攻击,或更准确地说,需要为每个用户记录单独的彩虹表)。强大的方法是使用大量的熵(如果可以,使用/dev/urandom),将64位随机数据存储为用户记录的一部分,并将其用作盐。要破解此方法的彩虹表将无法获得。 - MightyE
1
用户名和电子邮件地址如何作为盐值呢?它们非常可预测。 - President James K. Polk
关于第三点 - 即使您的网站本身不受攻击者的兴趣,您的用户数据库仍然对攻击者有用,因为很可能您的一半用户在 Gmail / Facebook / 其他有吸引力的网站上使用相同的密码。(例如最近的Gawker案件,导致Twitter垃圾邮件来自被攻击的帐户)。 - caf
@caf 是的,很有用。那又怎样?它已经被哈希了,如果你没有注意到的话。它应该如何使用那个数据库?为什么你们中没有人在评论之前试着去思考一下呢? - Your Common Sense
显然,如果你只使用简单的盐值(hash),攻击者会利用字典攻击来找到大部分或所有的密码。这不是理论上的问题;它已经发生过,并且还会再次发生。是在提出无根据的言论。 - caf
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接