为什么盐使字典攻击“不可能”?

时间:2010-08-25 13:50:01

标签: security hash salt dictionary-attack

更新:请注意我不是在询问盐是什么,彩虹表是什么,字典攻击是什么,或盐的目的是什么。我在查询:如果你知道用户的盐和哈希值,那么计算密码是不是很容易?

我理解这个过程,并在我的一些项目中自己实现。

s =  random salt
storedPassword = sha1(password + s)

在您存储的数据库中:

username | hashed_password | salt

我所看到的盐析的每次实施都会在密码的末尾添加盐,或者开始:

hashed_Password = sha1(s + password )
hashed_Password = sha1(password + s)

因此,来自一个值得他的盐(ha ha)的黑客的字典攻击只会针对上面列出的常见组合中存储的盐运行每个关键字。

当然,上述实现只是为黑客增加了另一个步骤,而没有真正解决潜在的问题?有什么替代方法可以解决这个问题,还是我误解了这个问题?

我唯一能想到的是有一个秘密混合算法,它以随机模式将salt和密码绑定在一起,或者将其他用户字段添加到散列过程中,这意味着黑客必须能够访问数据库AND将它们用于字典攻击的代码,以证明它是富有成效的。 (更新,正如评论中指出的那样,最好假设黑客可以访问您的所有信息,因此这可能不是最好的。)

让我举一个例子,说明我如何建议黑客使用密码和哈希列表破解用户数据库:

来自黑客数据库的数据:

RawPassword (not stored)  |  Hashed   |     Salt
--------------------------------------------------------
letmein                       WEFLS...       WEFOJFOFO...

通用密码字典:

   Common Password
   --------------
   letmein
   12345
   ...

对于每个用户记录,循环使用公共密码并对其进行哈希:

for each user in hacked_DB

    salt = users_salt
    hashed_pw = users_hashed_password

    for each common_password

        testhash = sha1(common_password + salt)
        if testhash = hashed_pw then
           //Match!  Users password = common_password
           //Lets visit the webpage and login now.
        end if

    next

next

我希望这能更好地说明我的观点。

鉴于10,000个常用密码和10,000个用户记录,我们需要计算100,000,000个哈希值以发现尽可能多的用户密码。可能需要几个小时,但这不是一个问题。

破解理论更新

我们假设我们是一个损坏的虚拟主机,它可以访问SHA1哈希和盐的数据库,以及混合它们的算法。该数据库有10,000个用户记录。

This site声称能够使用GPU每秒计算2,300,000,000个SHA1哈希值。 (在现实世界中,情况可能会变慢,但现在我们将使用引用的数字)。

  

(((95 ^ 4)/ 2300000000)/ 2)* 10000 = 177   秒

给定全范围的95个可打印ASCII字符,最大长度为4个字符,除以计算速率(变量)除以2(假设发现密码的平均时间平均需要50%的排列)对于10,000个用户,需要177秒来计算长度为< = 4的所有用户密码。

让我们稍微调整它以获得真实感。

  

(((36 ^ 7)/ 1000000000)/ 2)* 10000 = 2天

假设非大小写敏感,密码长度<= 7,只有字母数字字符,则需要4天才能解决10,000个用户记录,并且我将算法的速度减半以反映开销和非理想情况

重要的是要认识到这是一次线性暴力攻击,所有计算都是相互独立的,因此对于多个系统来说,这是一个完美的任务。 (IE很容易设置2台计算机从不同的端部运行攻击,这将是exectution时间的一半)。

考虑到递归散列密码1000次的情况,使这项任务的计算成本更高:

  <(>(36 ^ 7)/ 1 000 000 000)/ 2)* 1000   秒= 10.8839117小时

这表示最大长度为7个字母数字字符,执行速度低于一个用户的引用数字。

递归散列1,000次有效阻止了全面攻击,但针对用户数据的针对性攻击仍然容易受到攻击。

11 个答案:

答案 0 :(得分:62)

它不会阻止字典攻击。

它的作用是阻止设法获取密码文件副本的人使用rainbow table来确定哈希密码的来源。

但最终,它可能是暴力强迫的。该部分的答案是强制您的用户不要使用字典单词作为密码(例如,至少一个数字或特殊字符的最低要求)。

<强>更新

我之前应该提到这一点,但是一些(大多数?)密码系统为每个密码使用不同的盐,可能与密码本身一起存储。这使得单个彩虹表无用。这就是UNIX crypt库的工作方式,现代类UNIX操作系统已经使用新的哈希算法扩展了这个库。

我知道在较新版本的GNU crypt中添加了对SHA-256和SHA-512的支持。

答案 1 :(得分:30)

更确切地说,dictionary attack,即在详尽列表中尝试所有单词的攻击,并非“不可能”,但它会不切实际:{{3} }。

这与预先计算的字典攻击不同,例如涉及彩虹表的攻击,其中盐是否是秘密并不重要。

示例:使用64位盐(即8个字节),您需要在字典攻击中检查2 64 其他密码组合。使用包含200,000个单词的字典,您将不得不

  

200,000 * 2 64 = 3.69 * 10 24

在最坏的情况下进行测试 - 而不是没有盐的200,000次测试。

使用salt的另一个好处是攻击者无法从他的字典中预先计算密码哈希值。它只需要太多的时间和/或空间。

<强>更新

您的更新假定攻击者已经知道了盐(或者已经窃取了它)。这当然是一种不同的情况。攻击者仍然不可能使用预先计算的彩虹表。这里重要的是散列函数的速度。要使攻击不切实际,散列函数需要很慢。 MD5或SHA在这里不是很好的候选者,因为它们被设计为快速,更好的哈希算法候选者是Blowfish或它的一些变体。

更新2

关于保护密码哈希问题的一个很好的解读(远远超出原始问题,但仍然很有趣):

  

<强> each bit of salt doubles the amount of storage and computation required

文章的推论:使用 bcrypt (基于Blowfish)或 Eksblowfish 创建的盐渍哈希,允许您使用可配置的设置时间使哈希变慢。 / p>

答案 2 :(得分:30)

是的,sha1(salt |密码)只需要3天。这就是为什么好的密码存储算法使用1000次迭代哈希:你将需要8年。

答案 3 :(得分:17)

字典是一种结构,其中值由键索引。在预先计算的字典攻击的情况下,每个密钥是散列,并且对应的值是导致散列的密码。使用预先计算的字典,攻击者可以“立即”查找将生成必要哈希的密码以进行登录。

使用salt,存储字典所需的空间迅速增长......如此迅速,试图预先计算密码字典很快变得毫无意义。

最好的盐是从加密随机数发生器中随机选择的。八个字节是实际大小,超过16个字节没有用处。


Salt不仅仅是“让攻击者的工作更加刺激。”它消除了整个攻击类 - 使用预先计算的词典。

另一个元素是完全保护密码所必需的,这就是“加强密钥”。 一轮SHA-1不够好:一个安全的密码哈希算法应该非常计算速度慢。

许多人使用密钥派生函数PBKDF2将结果反馈给散列函数次。 “bcrypt”算法类似,使用缓慢的迭代密钥推导。

当散列操作非常慢时,预先计算的表对于攻击者来说越来越受欢迎。但是适当的盐会失败。


评论

以下是我对这个问题的评论。


如果没有盐,攻击者就不会使用“Update 2”中演示的方法。他只是在预先计算的表中进行查找,并在O(1)或O(log n)时间内获取密码(n是候选密码的数量)。 Salt就是阻止它并迫使他使用“Update 2”中显示的O(n)方法的原因。

一旦减少到O(n)攻击,我们必须考虑每次尝试需要多长时间。密钥加强可能导致循环中的每次尝试都花费一整秒,这意味着在10k用户上测试10k密码所需的时间将从3天延长到3 ...并且只有10k密码,你可能会在那个时候破解零密码。

你必须考虑攻击者将使用他能够使用的最快的工具,而不是PHP,因此数千次迭代而不是100次将是加强密钥的好参数。它应该花费很长时间来计算单个密码的哈希值。

密钥加强是标准密钥派生算法PBKDF1和PBKDF2的一部分,来自PKCS#5,它们制作了很好的密码混淆算法(“派生密钥”是“哈希”)。

StackOverflow上的很多用户都参考this article,因为这是对Jeff Atwood关于彩虹表危险的帖子的回应。这不是我最喜欢的文章,但它确实更详细地讨论了这些概念。


当然,您认为攻击者拥有一切:salt,hash,用户名。假设攻击者是一个腐败的托管公司员工,他将用户表转储到myprettypony.com粉丝上。他正在尝试恢复这些密码,因为他要转身看看你的小马粉丝是否在他们的citibank.com帐户上使用了相同的密码。

使用精心设计的密码方案,此人无法 恢复任何密码。

答案 4 :(得分:7)

腌制的目的是防止攻击者的努力摊销。

在没有盐的情况下,可以在世界上每个数据库中的每个用户上使用一个预先计算好的哈希密码条目表(例如,所有字母数字5字符串的MD5,易于在线查找)。

使用特定于站点的盐,攻击者必须自己计算表,然后才能在站点的所有用户上使用它。

对于每个用户的盐,攻击者必须分别为每个用户花费这笔费用。

当然,这并不能直接从词典中保护真正弱的密码,但它可以保护合理的强密码免受此摊销。

答案 5 :(得分:6)

另外 - 一个更加明确的观点 - 使用特定于用户的盐可以防止使用SAME密码检测到两个用户 - 它们的哈希值会匹配。这就是哈希很多次哈希(盐+用户名+密码)

的原因

如果您尝试保持哈希秘密,则攻击者也无法验证哈希值。

编辑 - 刚刚注意到主要观点是在上面的评论中做出的。

答案 6 :(得分:5)

实施盐以防止彩虹表攻击。彩虹表是预先计算的散列列表,这使得将散列转换为它的短语更加简单。你需要明白,除非我们有现代的哈希算法,否则腌制作为破解密码的现代预防是无效的。

因此,我们假设我们正在使用SHA1,充分利用此算法发现的最新漏洞,并且假设我们的计算机运行速度为1,000,000哈希/秒,it would take 5.3 million million million years to find a collision,所以是的PHP可以工作300 a第二,大woop,并不重要。我们之所以撒盐,是因为如果有人费心去生成所有常见的词典短语,(2 ^ 160人,欢迎来到2007年的时代利用)。

所以这是一个实际的数据库,有2个用户用于测试和管理目的。

RegistrationTime        UserName        UserPass    
1280185359.365591       briang      a50b63e927b3aebfc20cd783e0fc5321b0e5e8b5
1281546174.065087       test        5872548f2abfef8cb729cac14bc979462798d023

事实上,腌制方案是你的sha1(注册时间+用户名)。来吧,告诉我我的密码,这些是生产中的真实密码。你甚至可以坐在那里用PHP挖出一个单词列表。狂野。

我并不疯狂,我只知道这是安全的。为了好玩,测试的密码是testsha1(sha1(1281546174.065087 + test) + test) = 5872548f2abfef8cb729cac14bc979462798d023

您需要生成一个完整的彩虹表,其中27662aee8eee1cb5ab4917b09bdba31d091ab732用于 此用户。这意味着我实际上可以允许我的密码不会被一个彩虹表所破坏,黑客需要为27662aee8eee1cb5ab4917b09bdba31d091ab732生成一个完整的彩虹表进行测试,并再次为briang生成f3f7735311217529f2e020468004a2aa5b3dee7f。回想所有哈希值的530万年。想想存储2 ^ 80个哈希值(大约超过20 yottabytes)的大小,它不会发生。

不要将salting混淆为制作无法解码的哈希值的方法,这是防止彩虹表转换所有您的用户密码的一种方法。在这种技术水平上它是不可能的。

答案 7 :(得分:3)

字典攻击背后的想法是你拿一个哈希并找到密码,从中计算这个哈希,没有哈希计算。现在用盐渍密码做同样的事 - 你做不到。

不使用salt会使密码搜索像在数据库中查找一样简单。添加salt使攻击者执行所有可能密码的哈希计算(即使对于字典附加,这也会显着增加攻击时间)。

答案 8 :(得分:2)

简单来说:在没有salting的情况下,每个候选密码只需要进行一次散列,以便针对每个用户进行检查,在“已知Universe”(受损数据库集合)中的任何位置进行检查,其密码通过相同的算法进行哈希处理。使用salting时,如果可能的salt值的数量大大超过“已知Universe”中的用户数,则必须为每个将被测试的用户单独对每个候选密码进行散列。

答案 9 :(得分:2)

简单地说,腌制不会阻止哈希攻击(暴力或字典),它只会让它变得更难;攻击者要么需要找到腌制算法(如果正确实施将使用更多的迭代)或者强制算法,除非非常简单,否则几乎不可能。 Salting也几乎完全放弃了彩虹表查找的选项......

答案 10 :(得分:1)

Salt使Rainbow table攻击变得更加困难,因为它使单个密码哈希更难破解。想象一下,你有一个只有数字1的可怕密码。彩虹表攻击会立即破解。

现在假设数据库中的每个密码都有许多随机字符的长随机值。现在你糟糕的密码“1”作为1的散列加上一堆随机字符(盐)存储在数据库中,因此在这个例子中,彩虹表需要具有以下内容的散列:1。

因此,假设您的盐是安全且随机的,请说()%ISLDGHASKLU(%#%#,黑客的彩虹表需要有1 *()%ISLDGHASKLU的条目(* %#%#。现在使用彩虹表即使这个简单的密码也不再实用。