使用多种算法进行密码哈希处理

7

使用多个算法会使密码更安全吗?(还是更不安全?)

我想明确一下,我不是在讨论像这样做任何事情:

key = Hash(Hash(salt + password))

我在谈论使用两个独立的算法并进行匹配:

key1 = Hash1(user_salt1 + password)
key2 = Hash2(user_salt2 + password)

要求在身份验证时匹配两者。我看到有人建议这样可以消除冲突匹配,但我担心会产生意想不到的后果,例如创建“最弱链”情景或提供使用户数据库更容易破解的信息,因为此方法提供比单个密钥更多的数据。例如,将信息与哈希组合以更轻松地找到它们。另外,如果真正消除了冲突,理论上可以暴力破解实际密码而不仅仅是匹配的密码。事实上,你必须这样做才能完全暴力破解系统。
我实际上没有计划实施这一点,但我很好奇这是否比使用单个“key = Hash(user_salt + password)”的标准做法更好。
编辑:有很多好答案,总结一下,这应该是显而易见的,但是使用两者会创建一个最弱的链接,因为较弱的算法的匹配可以尝试与其他算法匹配。例如,如果您使用了一个弱(快速)MD5和一个PBKDF2,我会先暴力破解MD5,然后尝试任何匹配项与其他匹配,因此通过拥有MD5(或其他东西),您实际上会使情况变得更糟。此外,即使两者都属于更安全的集合(例如bcrypt + PBKDF2),您也会将暴露风险加倍。

1
你可能在http://crypto.stackexchange.com上更有好运。 - user395760
2
我相信一些银行实际上采用双重键哈希,具有双重输入方法。 - drum
1
@drum 我对进一步的解释很感兴趣。或者一个链接。 - svidgen
1
说碰撞不是大问题并不意味着不需要加盐。加盐可以防止预计算,它的目的不是为了防止两个唯一的密码哈希成相同的值。盐的目的是为了防止您预先计算大字典中的密码哈希值,然后将其与以后的哈希密码数据库进行匹配。 - Luke
@Luke - 我不确定这完全正确。如果您没有对密码进行加盐或对每个密码使用相同的盐值,那么可以访问数据库的攻击者可以查找具有相同密码哈希值(因此是相同密码)的帐户。这些帐户可能会成为基于常见密码/字典的攻击的目标。 - Eric Petroelje
@EricPetroelje 我想也许你误读了我的陈述。我认为你说的正是我所说的。 :) - Luke
4个回答

7

这只能帮助减少冲突的可能性。正如您所提到的,有几个缺点(最大的弱点之一)。

如果目标是减少冲突的可能性,最好的解决方案就是使用单个安全算法(例如bcrypt)和更大的哈希值。


你能详细说明一下最弱链接案例吗?我认为当你将结果链接/组合成单个值时,这就是为什么会出现这种情况(基本上哈希减少了可用数据,因此最弱的哈希暴露了整个密钥以进行暴力破解),但如果它们被独立存储并且都被强制匹配,那么情况是否仍然存在? - Paul
@Paul - 好吧,假设hash1是一个MD5哈希。假设密码为8个字符,并给定盐值,MD5哈希可以相对容易地被暴力破解。因此,无论你的第二个哈希有多好,攻击者都能够从MD5哈希中暴力破解密码。 - Eric Petroelje

6
现代哈希算法不需要担心碰撞问题。重点不在于确保数据库中每个哈希都是唯一的,而是确保在数据库被盗或意外泄漏时攻击者难以确定用户的实际密码。现代哈希算法错误地识别“错误”密码为“正确”密码的概率几乎为零,这可能更符合您的想法。
明确一点,你可能关注碰撞的两个主要原因是:
1. “正确”密码与提供的“错误”密码之间的碰撞可能允许使用“错误”密码进行认证。 2. 两个用户密码之间的碰撞可能会泄露用户A的密码,如果已知用户B的密码。
关注点1是通过使用强大/现代哈希算法(并避免极其反智的事情,如仅基于密码哈希查找用户记录)来解决的。关注点2是通过适当的加盐来解决的-即每个密码的“长度”唯一盐。让我强调一下,仍然需要正常加盐。
但是,如果将哈希添加到混合中,那么您只是给潜在攻击者提供了更多信息。我不确定是否当前存在任何已知的方法可以从一对哈希中“三角测量”消息数据(密码),但是通过包含另一个哈希,您不会获得显着的收益。这不值得冒险,因为可能存在一种利用额外信息的方法。

我认为你在这里忽略了一个微妙的点。理想情况下,数据库中的每个哈希值都是唯一的。这样,如果你的数据库被盗并且不法分子花时间破解用户A的密码,他们不会自动获得用户B的密码,即使它恰好与用户A的密码匹配。这就是盐的作用所在。盐还可以防止预计算,但我描述的情况实际上只是一种短期的预计算(我刚刚预先计算了它)。 - Luke
@Luke 理想情况下是这样的,但这不是重点。如果有盐值X和密码X的哈希值与有盐值Y和密码Y的哈希值相同,那么并不会显著地(如果有的话)危及任何一个密码。也就是说,并非所有的碰撞都是有意义的。无论如何,正确的加盐处理是必需的。 - svidgen
1
我同意。从@Paul的更新中来看,他似乎误解了一些东西。希望这些评论能够澄清。具体来说:“显然,碰撞不再是什么大问题了。虽然我还不确定这一点,所以我现在还会继续加密。” - Luke
好的,我想也许在我的表述上有一些语义上的不精确。我越想越不确定“无所谓”到底是什么意思了,因为按照我的理解,你必须回到很多年前才能找到这些碰撞会成为问题的时候。我将彻底删除第二点。真正重要的是,问题描述中所描述的方法是有缺陷的——当我第一次看到它时,我无法完全解释为什么。 - Paul
@Paul,实际上svidgen在这里说的是该方法是不必要的,因为它解决了一个不存在的问题。它解决了哈希算法采用两个不同的输入并产生相同输出的问题,而这在任何合理的哈希算法中都是统计学上不可能的。 - Luke

4
回答你的问题:
拥有唯一的salt比使用通用的salt更好。H(S1 + PW1),H(S2 + PW2) 使用多个算法可能比使用单个算法更好 H1(X),H2(Y)(但可能不是,正如svidgen所提到的那样)
然而,
这个问题的精神有些错误,原因如下:
1. 您不应该在没有安全专家的指导下自己设计安全协议。我知道这不是您自己的算法,但大多数安全问题都是由于错误使用而起的;算法本身通常是无懈可击的。
2. 您不应该使用hash(salt+password)来存储数据库中的密码。这是因为哈希是为了速度而设计的,而不是为了安全。在今天的硬件(特别是GPU处理)上找到旧算法中的哈希冲突有点容易。当然,您可以使用新的安全哈希算法(SHA-256或SHA-512),其中碰撞不是问题——但为什么要冒险呢?
你应该研究基于密码的密钥派生函数(PBKDF2),它们被设计成慢一些,以防止这种类型的攻击。通常需要结合加盐、安全哈希算法(SHA-256)并迭代几十万次。让函数运行大约需要1秒对于用户登录来说不是问题,他们不会注意到这样的减速。但对于攻击者来说,这是一场噩梦,因为他们必须针对每个尝试执行这些迭代;显着地减缓了任何暴力攻击。

看一下支持PBKDF加密的库可能是更好的方法。 Jasypt 是我最喜欢的用于Java加密的库之一。

请查看相关安全问题:如何安全地哈希密码 以及这个松散相关的SO问题


对于未来的读者,通常会在唯一的盐之外使用通用盐。这个幽默地称为“胡椒”的通用盐是一个秘密,而盐通常与密码存储在一起。 当然,这个秘密并不是不可能被发现的,但它增加了破解密码的难度。 - Charles Burns

0

在密码哈希中添加盐可以防止使用通用预先构建的哈希表。攻击者将被迫基于他们的单词列表和您的随机盐生成新表。

如上所述,哈希是为了快速设计的。要将它们用于密码存储,您需要减慢它们(大量嵌套重复)。

您可以创建自己的专用于密码的哈希方法。实质上,在salt+password上嵌套您喜欢的哈希并进行递归。

string MyAlgorithm(string data) {
  string temp = data;
  for i = 0 to X {
    temp = Hash3(Hash2(Hash1(temp)));
  }
}
result = MyAlgorithm("salt+password");

其中,“X”是大量重复的次数,足以在良好硬件上至少需要一秒钟的时间。正如其他地方提到的那样,这种延迟的目的是对于普通用户来说不重要(他们知道正确的密码并且只需等待一次),但对于攻击者来说却很重要(他必须为每个组合运行此过程)。当然,这都是为了学习而做的,可能更简单的方法是使用适当的现有API。


PBKDF2的标准化就是为了这个原因 - 一个人不应该自己实现PBKDF函数 - 而是应该从经过充分测试的库中选择一个。 - Justen
假设您遵循适当的安全程序,没有理由不实现自己的加密算法。如果您查看PBKDF2的源代码,它非常简单且功能有限。无论如何,使用更大/混合的HMAC集进行哈希处理是对攻击者的又一道障碍,这很有趣。 - Ioan
1
新的代码在这个特定的问题领域几乎总是比旧的代码不够安全。作为学术练习,它足够简单,但没有理由在生产环境中自己实现它。特别是因为:1.它已经存在,2.它是由专家编写的,3.通过发现和修补漏洞来经受时间的考验。 - Justen
+1 对 @Justen 的观点。在这个问题领域中有很多微妙的事情需要考虑。其中一些是完全不明显的,比如时序攻击甚至是电力波动和使用攻击。任何关于密码的潜在信息泄露都会危及其安全性(大小、一两个位的值等)。 - Luke
@Luke 我没有读完整个标准,但是看了一下OpenBSD实现的源代码,它所做的不过就是我所概述的那么点。虽然我理解计算机安全这个话题很广泛,但这个特定元素并不是最难的。此外,请注意我不会实现底层哈希算法,这些算法更加重要。 - Ioan

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