使用多种算法散列密码

时间:2013-01-15 15:51:25

标签: security hash

使用多种算法可以使密码更安全吗? (或更少?)

为了清楚起见,我不是在谈论做这样的事情:

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),你也可以将其中一个暴露给其中一个破坏。

4 个答案:

答案 0 :(得分:7)

这有助于减少碰撞的可能性。正如你所提到的,有几个缺点(最薄弱的环节是一个很大的缺点)。

如果目标是减少冲突的可能性,那么最好的解决方案就是使用具有更大散列的单个安全算法(例如bcrypt)。

答案 1 :(得分:6)

碰撞不是现代哈希算法所关注的问题。重点不在于确保数据库中的每个哈希都是唯一的。真正的重点是确保在您的数据库被盗或意外泄露的情况下,攻击者很难确定用户的实际密码。现代哈希算法将错误的密码识别为正确的密码的可能性实际上为零 - 这可能是您在此处获得的更多信息。

要明确的是,您可能会担心碰撞有两大原因。

  1. “正确”密码与提供的“错误”密码之间的冲突可能允许使用“错误”密码的用户进行身份验证。
  2. 如果用户B的密码已知,则两个用户密码之间的冲突可以“显示”用户A的密码。
  3. 通过使用强大/现代的哈希算法解决问题1(并避免非常反辉煌的事情,例如仅根据密码哈希来查找用户记录)。关注2通过适当的腌制解决 - 每个密码的“冗长”独特盐。让我强调,仍然需要适当的腌制

    但是,如果你在混音中添加哈希值,那么你只是给潜在的攻击者提供了更多信息。我不确定当前是什么从一对哈希中“三角测量”消息数据(密码)的任何已知方法,但是你没有通过包含另一个哈希来获得显着的收益。 是一种利用附加信息的方式,这是不值得冒险的。

答案 2 :(得分:4)

回答你的问题:

拥有独特的盐比使用通用盐更好。 H(S1 + PW1),H(S2 + PW2) 使用多个算法可能比使用单个H1(X),H2(Y)更好 (但可能没有,正如svidgen所提到的那样)

<强>然而

这个问题的精神有点不对,原因有两个:

  1. 如果没有安全专家的指导,您不应该提出自己的安全协议。我知道这不是你自己的算法,但大多数安全问题都是因为使用不当而引发的;算法本身通常都是气密的。

  2. 您不应该使用哈希(salt +密码)将密码存储在数据库中。这是因为散列设计得很快 - 不安全。使用今天的硬件(特别是使用GPU处理)在旧算法中查找散列冲突有点容易。您当然可以使用更新的安全哈希算法(SHA-256或SHA-512),其中碰撞不是问题 - 但为什么要冒险?

  3. 你应该研究基于密码的Key Derivation FunctionsPBKDF2),它们可以缓慢地阻止这种类型的攻击。通常它需要结合使用salting,安全哈希算法(SHA-256)和迭代几十万次。

    对于登录用户不会注意到这种减速的用户而言,使该功能花费大约一秒钟是没有问题的。但对于攻击者而言,这是一场噩梦,因为他们必须为每次尝试执行这些迭代;显着减缓任何蛮力企图。

    看看支持PBKDF加密的库是一种更好的方法。 Jasypt是Java加密的最爱之一。

    查看此相关安全问题:How to securely hash passwords 这与松散相关的SO question

答案 3 :(得分:0)

在密码哈希中添加了一个salt,以防止使用通用的预构建哈希表。攻击者将被迫根据他们的单词列表和随机盐一起生成新表。

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

您可以创建自己的密码特定散列方法。基本上,将您的首选哈希嵌套在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。