多次哈希密码是否更安全?


43

我读过几次书,存储密码时,对字符串进行“双散列”是一个很好的做法(例如,使用md5然后使用sha1,显然都使用了盐)。

我想第一个问题是,“这实际上正确吗?” 如果不是,那么请忽略此问题的其余部分:)

我问的原因是,从表面上看,我会说这是有道理的。但是,当我考虑它时,每次重新哈希(可能添加了一些东西)时,我所看到的就是最终“唯一性”的上限减小了……该界限与初始输入。

让我换一种说法:我们有x个字符串,这些字符串经过哈希处理后减少为y个可能的字符串。也就是说,第一组中有碰撞。现在从第二组返回到第三组,是否不可能发生同一件事(即,所有可能的“ y”字符串组中的冲突导致第三组出现相同的哈希)?

在我的脑海中,我看到的只是每个哈希函数调用的“漏斗”,将无限的可能性“漏斗”到有限的集合中,依此类推,但是显然每个调用都在它之前的有限集合上进行,给了我们一个设置不大于输入。

也许有一个例子可以解释我的漫步?取'hash_function_a',它将给'a'和'b'哈希值'1',并将给'c'和'd'哈希值'2'。使用此功能存储密码,即使密码为“ a”,我也可以使用密码“ b”。

取'hash_function_b',它将为'1'和'2'提供哈希值'3'。如果我将用作“ hash_function_a”之后的“第二哈希”,那么即使密码为“ a”,我也可以使用“ b”,“ c”或“ d”。

最重要的是,我知道应该使用盐,但是它们并没有真正改变我们每次将“ x”输入映射到“小于x”输出的事实。我不认为

有人可以告诉我我在这里想念什么吗?

谢谢!

编辑:对于它的价值,我自己不做,我使用bcrypt。而且我并不真正担心它对于“黑客”的“耗尽周期”是否有用。我真的只是想知道从哈希冲突的角度来看,该过程是否会降低“安全性”。


2
@ S.Lott:我真的看不出如何回答实际的问题,尽管...它的意思是“不要自己做,用这个东西”或“好好花时间!”。 ..这两个答案都“实际上是否更安全”。再说一次,除非我错过了什么。
水仙

@MetalMikester:是的,那是昨天的文章:thedailywtf.com/Articles/Bulletproof-Encryption.aspx
FrustratedWithFormsDesigner

这不是IT安全性的主题,但看起来确实很适合密码术。实际上,它看起来与那里的这个问题极为相似。

我知道有一家公司想使用无盐MD5(password)。我们说这是不安全的,所以他们建议MD5(MD5(password))改用...
配置器

接受的答案不是正确的答案!
markus 2012年

Answers:


27

这更适合security.stackexchange但...

问题所在

hash1(hash2(hash3(...hashn(pass+salt)+salt)+salt)...)+salt)

是,它的强度仅与链中最弱的哈希函数一样强。例如,如果hashn(最里面的哈希)发生冲突,则整个哈希链都会发生冲突(无论该链中还有其他哈希)。

一个更强大的链条将是

hash1(hash2(hash3(...hashn(pass + salt) + pass + salt) + pass + salt)...) + pass + salt)

在这里,我们避免了早期冲突问题,并且基本上生成了一个盐,该盐取决于最终哈希的密码。

而且,如果链中的某个步骤发生冲突,也没关系,因为在下一步中,密码将再次使用,并且对于不同的密码应给出不同的结果。


因此,现在我看到在下一轮哈希中添加“密码+盐”作为盐可能会增加可能进入漏斗的“材料”的数量,现在我只需要了解“多少”即可。谢谢。
水仙

实际上,我想我确实知道了:通过将密码强制进入哈希的每一层,实际上是通过本质上要求“冲突密码”和真实密码在每个“调用”中具有匹配的哈希来减少可能发生的冲突的次数, 对?我在想我丢失了“在每一层都输入密码”部分!再次感谢。
水仙

@Narcissus no prob,它还具有允许较弱的内部哈希值(只要外部/最终哈希值很强)的好处,因为内部哈希值只会为下一遍生成盐
棘轮怪胎

哼,我认为这个问题要更大(更深)。使用Rainbow攻击,您可以只考虑所有哈希值来生成表,而问题仍然存在。
woliveirajr 2011年

4
@Narcissus:一个简短的答案:是的,它并不安全。是的,它的安全性可能更低
woliveirajr 2011年

54

使用不同的哈希算法不是一个好主意-它将减少而不是增加熵。

但是,假设您具有加密功能强的哈希算法和良好的算法,那么多次应用相同的哈希函数会使哈希过程的计算量更大。这样做的好处是,当其他破解密码哈希的方法失败(猜测,字典攻击,彩虹表等),并且攻击者被迫采用蛮力技术时,花更长的时间才能尝试每个密码,这仅仅是因为他们必须更频繁地应用相同的哈希函数。因此,如果一轮散列需要一个月的暴力破解,则将其应用十二次将使估计时间增加到一年。

最近的哈希算法(如bcrypt)基于此思想。它们包含一个参数来控制哈希的计算复杂度,因此您可以随着硬件速度的发展对其进行扩展:当硬件的速度提高两倍时,您就需要增加复杂度来进行补偿,因此蛮力地花费了您的时间。哈希值大致保持不变。


2
这是正确的答案!
markus 2012年

@markus:根据我阅读的讨论,这是正确的,因为添加的“和好盐”已被接受的答案解决了,不是吗?为什么这是正确的,却是公认的答案呢?
水仙2012年

这是正确的答案,因为多次应用同一哈希函数(参数化)的唯一原因是您可以使用此迭代来调整以适应更快的硬件。否则,多次哈希将无益。
markus 2012年

@Narcissus这里的关键是熵。使用相同方法进行多次哈希处理与使用不同方法进行多次哈希处理之间存在差异。
sakisk 2013年

3

除非您愿意参加密码学和/或安全工程课程,否则请勿尝试编写自己的密码哈希方案。

您应该使用完善的密码散列实现,该实现又应使用密钥派生函数(KDF),例如PBKDF2,bcrypt,scrypt或更新的Argon2。

好的KDF包含一个工作因子,通常会进行多次迭代,以增加离线攻击的成本。可以说这些KDF多次使用相同的算法对密码进行哈希处理。正如其他人所指出的,使用多消息摘要算法毫无意义。



1
@gnat出于某种原因,我想念您关于被阻止URL的评论。我已将其替换为Wikipedia的链接。
Erwan Legrand

2

通常,您不需要使用多个哈希算法。

您需要做的是:

使用盐:盐不仅用于使您的密码更安全,还用于防止彩虹表攻击。这样,尝试为存储在系统中的密码预先计算哈希值的工作将更加艰巨。

使用多种交互方式:而不是仅做SHA(密码+盐),而是做SHA(SHA(SHA(SHA(SHA(... SHA(... 或者,以其他方式表示:

hash = sha(password + salt)
for i=1 , i=5000, i++ {
    hash = sha(hash + salt);
}

最后,选择一个好的哈希函数。SHA,MD5等不好,因为它们太快了。由于要使用散列进行保护,因此最好使用较慢的散列。例如,看看BcryptPBKDF2Scrypt

编辑:观察后,让我们尝试看一些要点(对不起,请长解释一下,因为它可能帮助其他人寻找相似的答案):

如果您的系统是安全的,那么就像没人能访问存储的密码一样,您就不需要哈希了。密码是秘密的,没有人知道。

但是没有人可以确保带有密码的数据库将被盗。窃取数据库,获取所有密码。好的,您的系统和公司将遭受所有的后果。因此,我们可以尝试避免此密码泄漏。

注意 ,我们现在不担心在线攻击。对于一种在线攻击,最好的解决方案是在输入错误密码后放慢速度,在尝试几次后锁定帐户,等等。因此,使用哪种方式加密,散列,存储密码都无关紧要。在线攻击是放慢密码输入的问题

因此,回到don't let them take my plain passwords问题所在。答案很简单:不要将它们存储为纯文本格式。好的,我知道了。

如何避免呢?

加密密码(?)。但是,正如您所知,如果您对其进行加密,那么只要拥有正确的密钥,就可以将其解密。您最终将遇到“在哪里隐藏”密钥的问题。嗯,不好,因为他们得到了您的数据库,所以他们可以得到您的密钥。好的,我们不要使用它。

因此,另一种方法是:让我们将密码转换成其他不可逆的方式并将其存储。为了验证所提供的密码是否正确,我们再次执行相同的过程,并检查两个转换后的值是否匹配。如果它们匹配=提供了正确的密码。

好的,到目前为止很好。让我们在密码中使用一些MD5哈希值。但是...如果某人拥有我们存储的密码的哈希值,则他可以拥有很大的计算机能力来计算每个可能的密码(蛮力)的MD5哈希值,因此他可以找到原始密码。或者,甚至更糟的是,他可以存储所有字符组合中的所有MD5,并轻松找到密码。因此,请做很多迭代操作,使HASH(HASH(HASH()))变得更加困难,因为这将花费更多时间。

但是即使可以绕开它,彩虹表的创建也正是为了加快这种保护的速度。

因此,让我们在上面加一些盐。这样,在每次交互时,盐都会再次使用。考虑到每次都添加盐,一个试图攻击密码的人将不得不生成彩虹表。并且当他生成该彩虹表时,由于它是用一种盐生成的,因此他将不得不再次用另一种盐进行计算,因此他将不得不花一些时间来输入每个密码(=每个盐)。Salt不会为密码增加“更多复杂性”,只会使攻击者失去时间来生成彩虹表,如果您为每个密码使用一个Salt,则从一个Salt到另一个密码的表是无用的。

并且使用多个哈希将对这里有所帮助吗?不会。产生特定彩虹攻击的人无论如何都可以使用一个或多个哈希来生成它。

而且使用多个哈希会导致您遇到一个问题:它与您使用的最弱哈希一样安全。如果有人在一种哈希算法中发现冲突,则在迭代过程的任何时候都将利用该哈希来破解密码。因此,使用更多的哈希算法不会带来任何好处,最好只选择一种算法。并使用它。而且,如果您曾经听说它已损坏,请考虑如何在应用程序中对其进行更改。

以及为什么使用bcrypt或类似的东西(您说要使用它):因为攻击者将不得不花费更多的时间来生成表。这就是使用MD5 +等待(3秒)无济于事的原因:无论如何,攻击将处于脱机状态,因此攻击者可以生成表而没有延迟(3秒)。


2
糟糕!抱歉,我的评论(关于通过timeout参数故意使哈希变慢)并不是要认真对待...我想我最近对Dilbert的阅读太多了。
FrustratedWithFormsDesigner

2
sha(sha(sha(..。)))并不比sha更安全。如果sha函数的熵不是最大,则实际上安全性较低。
deadalnix 2011年

1
@deadalnix:值得一提的是,它并没有使恢复原始密码变得更加容易,但是却使得生成冲突密码变得更加容易,这是必需的。
布莱恩·伯特彻

1
@deadalnix,我以Dale Gribble的声音阅读了该评论。
jiggy

1
@deadalnix:sha(sha(sha()()))的目标不是,也从来没有,是要增加熵。熵只是由初始用户选择其密码而产生的,其他所有内容(哈希,盐等)都只是为了减慢暴力攻击的速度。如果有人能够获取包含密码的数据库,那么他也可能会获得用于哈希密码的代码,因此任何硬编码盐也将为人所知
woliveirajr

-1

我的理解是,使用多种哈希算法将击败Rainbow表。使用优质的盐也可以,但是我想这是第二层保护。


4
嗯,这变化不大。可以将“多重哈希”功能视为一种并且将其视为。
deadalnix

2
使用多种哈希技术或迭代并不能克服彩虹表。如果攻击者拥有您的数据库,并且具有用于生成哈希的方法,则攻击者可以生成彩虹表来攻击数据库中的所有密码。SALTS防止了彩虹表攻击,因为它们阻止了攻击者生成单个查询字典来攻击(例如,所有8个字符或更少的密码)。
埃里克(Erik)

-1

这不是更安全。但是,您具有使用相同功能多次基于哈希的识别协议。

就是这样。存储的值是计算机A中的hash ^ n(pass)。A要求B进行身份验证,并将B赋予整数n。B执行计算hash ^(n-1)(pass)并将其发送回A。

检查hash(hash ^(n-1)(pass))== hash ^ n(pass)。如果为真,则完成身份验证。但是,然后,A商店hash ^(n-1)(pass)和下一次身份验证将给B n-1而不是n。

这样可以确保永远不会以明文形式交换密码,确保A永远不知道密码是什么,并且通过重播来保护身份验证。然而,这具有需要有限寿命的密码的缺点。当n达到值2时,必须在身份验证后选择新密码。

多重哈希的另一个用途是工具HMAC,以确保请求的身份验证和完整性。有关HMAC的更多信息,请参见http://en.wikipedia.org/wiki/HMAC

在现实世界中,大多数情况下使用多重哈希是过大的。就您而言,似乎如此。请注意,如果您使用多个哈希函数,它们将不会全部具有相同的熵,因此这会降低哈希的强度。例如,md5的熵比sha1小,因此在md5上使用sha1不会提高哈希的强度。该强度通常等于较弱哈希函数的强度。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.