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


85

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

我了解该过程,并在我的一些项目中亲自实施了该过程。

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

在您存储的数据库中:

username | hashed_password | salt

我所见过的每一种盐化实现都在密码末尾或开头添加盐分:

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

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

当然,上述实现只是为黑客增加了又一步,而没有真正解决根本问题?有什么替代方案可以解决此问题,还是我误解了该问题?

我唯一想做的是拥有一个秘密混合算法,该算法以随机模式将盐和密码绑在一起,或者将其他用户字段添加到哈希过程中,这意味着黑客将不得不访问数据库并绑上代码他们通过字典攻击证明卓有成效。(更新,如评论中指出的那样,最好假设黑客可以访问您的所有信息,所以这可能不是最好的)。

让我举一个例子,说明我如何建议黑客使用一系列密码和哈希值来入侵用户数据库:

来自被黑数据库的数据:

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个哈希值才能发现尽可能多的用户密码。可能要花费几个小时,但这并不是真正的问题。

开裂理论的最新进展

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

该站点声称能够使用GPU每秒计算2300,000,000 SHA1哈希。(在现实世界中,情况可能会变慢,但现在我们将使用引用的数字)。

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

给定一整套95个可打印ASCII字符,最大长度为4个字符,再除以计算率(变量)再除以2(假设发现密码的平均时间平均需要50%的排列)用户计算长度小于等于4的所有用户密码将花费177秒。

让我们为现实做些调整。

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

假设不区分大小写,密码长度<= 7,仅字母数字字符,则要花4天的时间才能解决10,000条用户记录,并且我将算法的速度减半以反映开销和不理想的情况。

重要的是要认识到这是线性蛮力攻击,所有计算彼此独立,因此这是解决多个系统的理想任务。(即,IE易于设置两台从不同端运行攻击的计算机,这将使执行时间减少一半)。

考虑到递归地对密码进行哈希处理1000次以使此任务在计算上更加昂贵的情况:

((((36 ^ 7)/ 1000000000000)/ 2)* 1000秒= 10.8839117小时

这表示最大长度为7个字母数字字符,对于一个用户而言,其执行速度不到引用报价的一半。

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


12
撒盐的全部目的是防止您能够查看散列密码并看到多个用户具有相同的散列(因此也具有相同的密码)。不加盐就可以使用哈希算法并生成所有可能的哈希,然后对该哈希进行粗略搜索。由于算法永远不会改变,因此对于攻击者来说是可预测的,加盐只会使其变得更加困难。
BeRecursive

25
因为薄脆饼干就像一样,盐使皮肤上的粘液变干并杀死它们。
TED 2010年

6
@TED:我更喜欢咸饼干。盐味的ug,不是很多。
FrustratedWithFormsDesigner 2010年

3
@Tom-在您的示例攻击中。如果没有盐,那么攻击者可以“针对每个常用密码,对密码进行哈希处理。这是否与一个或多个用户匹配?是的,我有他们的密码”-攻击者可以“并行”攻击所有密码。 ,无需额外费用。
Damien_The_Unbeliever

3
@Tom Gullen-您只有一半的图片。没有盐,攻击者将不会使用您在“更新2”中演示的方法。他只需在表中进行查找,然后以O(1)或O(log n)的时间(n是候选密码的数量)获得密码。Salt阻止了这种情况,并迫使他使用您演示的O(n)方法。另一种技术(密钥加强)可能会导致循环中的每次尝试花费一整秒的时间,这意味着执行这些测试将需要3年的时间...而且只有1万个密码,您很可能会破解零个密码时间。
erickson 2010年

Answers:


31

是的,sha3(盐|密码)只需要3天。这就是为什么好的密码存储算法使用1000迭代哈希的原因:您将需要8年的时间。


3
+1,迄今为止最简洁明了的答案,我不知道这是一个选择。
汤姆·古伦

显然,您从未在系统上执行过哈希基准测试。您每秒可以进行数百万次sha1计算。一千发对攻击者毫无意义。也为-1,因为sha1是一个损坏的哈希函数。
rook

显然我使用的是问题的名字和数字。如果您听说过诸如主题和清晰度之类的事情……哦,是鲁克。没关系。
大火

1
@Rook,发一千发意味着蛮力将需要1000倍的时间。对我来说似乎是个好功能。
Tom Gullen

如果攻击者可以猜出密码,那么登录密码是否相同(或有什么东西对我
有用

62

它不会阻止字典攻击。

它的作用是阻止设法使用彩虹表获取密码文件副本的人使用哈希找出密码是什么。

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

更新

我应该早先提到过这一点,但是某些(大多数?)密码系统对每个密码使用不同的盐,可能与密码本身一起存储。这使得一个彩虹桌子毫无用处。UNIX crypt库就是这样工作的,并且现代的类UNIX操作系统已使用新的哈希算法扩展了该库。

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


17
+1 Salt阻止使用预先计算的哈希表(彩虹表)。攻击者必须重新开始。
伊恩·博伊德

2
在PHP中,可以使用mcrypt或bcrypt库进行比md5或sha1更好的加密。如果您对md5或sha1感到困惑,则应该“拉伸”,在此之前,您对密码进行了1000次哈希运算,然后才能访问数据库中存储的内容。这使熵保持不变,但是增加了计算哈希的时间。
Malfist 2010年

2
@Tom Gullen,您正在阅读哪些文章?自称专家或同行评审的科学期刊文章?
Malfist 2010年

7
这是您的普通Joe开发人员撰写有关如何编写“安全”系统的博客/帮助文章。安全性不是您可以选择的,它需要广泛的知识。这不公平吗?大概。安全吗?到一个程度。有安全专家的原因。但话又说回来,并非所有事物都必须像诺克斯堡一样安全。最好的策略是使用由这些专家设计的预建系统,并对其进行修改以满足您的需求。
Malfist 2010年

3
@Michael:使用更长的盐,您需要预先计算所有可能的盐值,以使其显示在彩虹表中。关键是您不会对所有密码保持一致,而是为每个密码随机选择,然后将其存储在数据库中存储的哈希密码旁边。因此,黑客将需要在Rainbow表中为每种可能的高价值盐添加一个条目,从而导致表太大而无法实现,这就是重点。
科林·德克鲁

31

更准确地说,字典式攻击(即尝试使用详尽列表中的所有单词的攻击)不是“不可能”的,但它是不切实际的盐的每一位使所需的存储和计算量增加了一倍

这与预先计算的字典攻击(例如涉及彩虹表的攻击)不同,在这种攻击中,盐是否为秘密都不重要。

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

200,000 * 2 64 = 3.69 * 10 24

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

使用salt的另一个好处是,攻击者无法从其字典中预先计算密码哈希。这将仅花费太多时间和/或空间。

更新资料

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

更新2

总体上,关于保护密码哈希的问题,这是一本不错的书(远远超出了最初的问题,但仍然很有趣):

足够使用Rainbow表:您需要了解的安全密码方案

本文的推论:使用由bcrypt(基于Blowfish)或Eksblowfish创建的盐腌哈希,这些盐哈希允许您使用可配置的设置时间来使哈希变慢。


4
@Tom Gullen-即使使用合理的强大密码策略,由于所有密码的可能性也不相同(因为人们选择助记符而不是RNG来选择它们),即使是拥有数亿或数十亿候选人的字典也可能会获得一定的成功。 。该大小的词典如果不使用盐对商品系统precomputable。如果使用盐,则攻击者每次都必须重新计算哈希,并且如果执行了足够的哈希迭代,则攻击者的攻击速度可以减慢到每秒几次尝试。
erickson 2010年

3
-1对我来说:保守秘密完全不是盐的重点。无论如何,您都需要它们可访问以检查密码,因此任何试图将它们保密的尝试都可能通过增加复杂性而不是实际成功而使系统更加脆弱。
Michael Borgwardt 2010年

2
@ 0xA3:再次:攻击者不知道这不是盐。您的计算机需要以某种方式访问​​它,因此侵入计算机的攻击者也可以获取它。攻击者不知道盐的任何情况都是红色鲱鱼。
Michael Borgwardt

1
我认为值得一提的是,链接文章误描述了彩虹表。他描述的是一个简单的字典附件。彩虹表确实有很大的不同(并且有些复杂)。关于彩虹表如何真正工作的相当不错的解释:kestas.kuliukas.com/RainbowTables
Jerry Coffin 2010年

3
-1表示“当然,盐必须保密”。如果攻击者可以访问您的密码哈希,那么他也将拥有您的盐-您需要的是每用户盐,而不是通过隐藏“盐”来确保安全。
snemarch

17

字典是一种结构,其中的值由键索引。在预先计算的字典攻击的情况下,每个密钥是一个哈希,而对应的值是一个导致哈希的密码。有了预先计算的字典,攻击者可以“立即”查找密码,该密码将产生登录所需的哈希值。

有了盐,存储字典所需的空间就会迅速增加……如此之快,以至于试图预先计算密码字典很快就变得毫无意义。

最好的盐是从密码随机数生成器中随机选择的。实际大小为8个字节,超过16个字节毫无用处。


Salt所做的不只是“使攻击者的工作更具刺激性”。它消除了整个攻击类别-使用预先计算的字典。

要完全保护密码,另一个要素是必需的,即“密钥加强”。一轮SHA-1还不够好:安全的密码哈希算法在计算上应该非常慢。

许多人使用PBKDF2(一种密钥派生功能),将结果反馈到哈希函数数千次。“ bcrypt”算法与之类似,只是使用了缓慢的迭代密钥推导。

当散列操作非常慢时,攻击者越来越需要预先计算的表。但是适当的食盐会使这种方法失败。


评论

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


没有盐,攻击者将不会使用“更新2”中演示的方法。他只需在预先计算的表中进行查找,然后以O(1)或O(log n)的时间(n是候选密码的数量)获得密码。Salt阻止了这种情况,并迫使他使用“更新2”中显示的O(n)方法。

一旦降低为O(n)攻击,我们必须考虑每次尝试需要多长时间。密钥加强可能会使循环中的每次尝试花费一整秒,这意味着在1万个用户上测试1万个密码所需的时间将从3天延长到3……而只有1万个密码,您很可能会破解零当时的密码。

您必须考虑到,攻击者将使用他可以使用的最快的工具(而不是PHP),因此数千次迭代而不是100次迭代将是增强密钥的一个好参数。计算单个密码的哈希值需要花费很大的时间。

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

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


当然,您假设攻击者拥有一切:盐,哈希,用户名。假定攻击者是一位腐败的托管公司员工,他将用户表转储到myprettypony.com爱好者站点上。他正在尝试恢复这些密码,因为他将转过身来看看您的小马球迷是否在其citibank.com帐户上使用了相同的密码。

使用精心设计的密码方案,此人将不可能恢复任何密码。


1
我认为Tom是“字典攻击”,是指尝试使用已知的弱密码(即直接从人类语言词典中删除),而不是预先计算的哈希明文表-这也是我在阅读“字典”时首先想到的在这种情况下。
Michael Borgwardt

@Michael Borgwardt:我同意,@ erickson指的是预先计算的字典攻击。
Dirk Vollmar,2010年

1
Salt停止了预先计算的字典攻击。按键强化可阻止字典攻击。两者必须一起使用才能进行安全的密码身份验证。
埃里克森(Erickson)2010年

我的意思是简单的英语桌子。该问题旨在解决如何阻止黑客为每个用户帐户解决所有可能的哈希组合的问题
Tom Gullen

7

加盐的目的是防止攻击者的努力摊销。

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

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

使用每用户盐,攻击者必须为每个用户分别花费此精力。

当然,这对于直接保护字典中的弱密码没有多大作用,但是可以保护合理的强密码以免摊销。


1
简短而准确的答案-值得一提的是,无需添加盐或使用全站点范围的盐,您就可以轻松发现使用相同密码的用户,并且只需蛮力就可以。使用每用户盐,您将无法做到这一点。
2010年

6

另外-还有一个重要的要点-使用特定于用户的盐会阻止使用SAME密码检测到两个用户-他们的哈希值会匹配。这就是为什么很多次哈希是哈希(盐+用户名+密码)的原因

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

编辑-刚刚注意到要点在上面的评论中。


1
您应该进行编辑以指定每个用户的盐;使用站点范围盐的站点仍将允许您检测相同的密码。
2010年

@snemarch-是的,非常感谢您的重要贡献!
多米尼克·韦伯

5

实施盐预防彩虹表攻击。彩虹表是预先计算的哈希表的列表,这使得将哈希表转换为其短语变得更加简单。您需要了解,除非我们拥有现代的哈希算法,否则盐析不能有效地防止破解密码。

因此,可以说我们正在与SHA1合作,利用此算法最近发现的漏洞,并假设我们有一台运行速度为1,000,000哈希/秒的计算机,要花530万亿亿年的时间才能发现碰撞,所以php可以每秒工作300次,这并不重要。我们之所以吃盐,是因为如果有人不愿意生成所有常见的词典短语(2 ^ 160个人,欢迎使用2007时代的漏洞利用)。

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

RegistrationTime        UserName        UserPass    
1280185359.365591       briang      a50b63e927b3aebfc20cd783e0fc5321b0e5e8b5
1281546174.065087       test        5872548f2abfef8cb729cac14bc979462798d023

实际上,加盐方案就是您的sha1(注册时间+用户名)。告诉我我的密码,这些是生产中的真实密码。您甚至可以坐在那里,在php中散列单词列表。去野外。

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

您将需要生成perpended整个彩虹表27662aee8eee1cb5ab4917b09bdba31d091ab732只是该用户。这意味着我实际上可以允许我的密码不完全被单个彩虹表所破坏,黑客需要为27662aee8eee1cb5ab4917b09bdba31d091ab732生成整个彩虹表进行测试,并再次为briang生成f3f7735311217529f2e020468004a2aa5b3dee7f。回想一下530万亿年的所有哈希值。考虑一下仅存储2 ^ 80个哈希(远超过20 yobytes)的大小,这将不会发生。

不要混淆加盐作为散列您从未解码过的哈希的方法,这是防止Rainbow表转换所有用户密码的方法。在这种技术水平上这是不可能的。


我了解什么是彩虹桌,但您没有回答我的问题。如果您为我提供了加盐算法,哈希密码和盐,那么是的,我可能会在几分钟之内告诉您密码。
汤姆·古伦

把钱放在嘴里吗?
隐身于2010年

可以,但是您只是告诉我示例中的密码,请给我一个盐,哈希密码,以及如何将盐+密码(非递归)组合在一起,只要密码<= 5个小写字母数字字符(无空格/特殊字符),我会让您知道此框中的内容。如果您希望我按照您的建议在上面花钱,请告诉我,尽管我对几分钟的评论可能被严重低估了,但是在几个小时内可以。
汤姆·古伦

1
实际上可能是几秒钟,请参阅golubev.com/hashgpu.htm,该文件使用GPU来计算为“每秒2300M / s SHA1哈希”。我们提供了95个ASCII字符(范围为1-6个字符),我们可以在不到6分钟的时间内破解它。如果我们只有小写字母数字字符,则长度不超过25分钟的字符数最多为8个字符。使用10,000个用户记录的数据库,我们可以在<200秒内找到全部4个char完整ASCII密码(((((95 ^ 4)/ 2300000000)/ 2)* 10000)。(比引用更多的开销,并且引用的GPU速度可能是理想的情况)。
汤姆·古伦

是的,撒盐不会阻止您暴力破解该密码。如果用户具有大约10个字符的密码,则使您更难生成((10 ^ 5)*(94 ^ 10))= 10 ^ 24,这比没有哈希的10 ^ 19难得多。再一次,这不是要让一个密码很难破解,而是要让预处理彩虹表无法破解所有密码。(并在这里检查我的数学,但我相信每个人的密码10 ^ 25/2300000000/60/60/24/365/1000 = 137869〜milinea)。如果我们想要更强壮的密码,我们不给它们加盐,则可以使用Diffie-Hellman密钥交换之类的工具。
隐身于2010年

3

词典攻击背后的想法是,您获取一个哈希并找到用于计算哈希的密码,而无需计算哈希。现在,使用加盐密码进行相同操作-您不能。

不使用盐会使密码搜索与在数据库中查找一样容易。添加盐会使攻击者对所有可能的密码进行哈希计算(即使使用字典连接,这也会大大增加攻击时间)。


在OP的情况下,攻击者已经从数据库中盐,以及将不得不想尽盐与在“字典”中的每个条目。...我认为。
FrustratedWithFormsDesigner

2

用最简单的术语:无需加盐,每个候选密码只需要进行一次哈希处理,即可针对“用户”(通过相同算法对哈希进行哈希处理)的“已知Universe”(受感染数据库的集合)中的每个用户进行检查。使用加盐功能时,如果可能的加盐值数量大大超过“已知Universe”中的用户数量,则必须针对将要针对其测试的每个用户分别散列每个候选密码。


2

简而言之,加盐并不能防止哈希(攻击力或字典)受到攻击,只会使其变得更困难;攻击者要么需要找到盐析算法(如果实施得当,将利用更多的迭代),要么是蛮力的算法,除非非常简单,否则几乎不可能实现。加盐几乎也完全放弃了彩虹表查找的选项。


1

盐使彩虹表攻击变得更加困难,因为它使单个密码哈希变得很难破解。想象一下,您有一个仅1号的可怕密码。彩虹表攻击将立即破解该密码。

现在,假设数据库中的每个密码都带有许多随机字符的长随机值。现在,您的糟糕密码“ 1”作为哈希值1加一堆随机字符(盐)存储在数据库中,因此在此示例中,rainbow表需要具有类似以下内容的哈希值:1。

因此,假设您的食盐是安全且随机的,例如说()%ISLDGHASKLU(%#%#,则黑客的彩虹表需要输入1 *()%ISLDGHASKLU(*%#%#。)现在使用彩虹表甚至这个简单的密码也不再可行。


请参阅更新#2,您将只拥有原始密码,并针对每个用户记录针对盐计算所有哈希值。
汤姆·古伦

2
当然,汤姆,我同意,但要点是,如果使用盐,黑客必须 每个密码执行一次难看的耗时过程。因此,盐的确会使使用彩虹桌变得更加困难。
科里·豪斯

3
@Tom Gullen:仅在使用全站点范围的盐时,才可以生成盐渍彩虹表;每位用户加盐使彩虹表攻击几乎毫无用处。
2010年
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.