密码盐如何帮助抵抗彩虹表攻击?


220

我在理解对密码加盐的目的时遇到了一些麻烦。据我了解,主要用途是阻止彩虹表攻击。但是,我见过的实现此问题的方法似乎并没有真正使问题变得更难。

我看过许多教程建议将盐用于以下用途:

$hash =  md5($salt.$password)

原因是哈希现在不映射到原始密码,而是密码和盐的组合。但是说$salt=foo$password=bar$hash=3858f62230ac3c915f300c664312c63f。现在,拥有彩虹表的人可以反转哈希并提出输入“ foobar”。然后,他们可以尝试所有密码组合(f,fo,foo,... oobar,obar,bar,ar,ar)。可能需要花费几毫秒的时间才能获取密码,但除此之外没有多少其他信息。

我见过的另一种用法是在我的linux系统上。在/ etc / shadow中,哈希密码实际上 salt 存储在一起。例如,盐“ foo”和密码“ bar”将散列为此:$1$foo$te5SBM.7C25fFDu6bIRbX1。如果黑客以某种方式能够获得此文件,那么我就看不到salt的用途是什么,因为te5SBM.7C25fFDu6bIRbX已知的反向哈希包含“ foo”。

感谢您提供的任何信息。

编辑:感谢您的帮助。总而言之,盐使散列密码变得更加复杂,因此使其不太可能存在于预先计算的彩虹表中。我之前误解的是我以为所有哈希都存在一个彩虹表。




此外,此处已更新-使用md5哈希不再是最佳实践。stackoverflow.com/questions/12724935/salt-and-passwords
StuartLC 2012年

感谢您的编辑。我有同样的疑问,现在可以澄清。因此,“盐”的真正含义是首先使Rainbow表不太可能包含掺假(加盐)密码的哈希。:D
Vaibhav

Answers:


237

破解单个密码时,公共盐不会使字典攻击变得更加困难。正如您所指出的,攻击者可以访问哈希密码和密码,因此在进行字典攻击时,她可以在尝试破解密码时简单地使用已知的密码。

公开的代码有两件事:破解大量密码更加耗时,并且使彩虹表无法使用。

要了解第一个,请想象一个包含数百个用户名和密码的密码文件。不加盐,我可以计算“ md5(attempt [0])”,然后扫描文件以查看该哈希是否在任何地方显示。如果存在盐,则我必须计算“ md5(salt [a]。try [0])”,与条目A比较,然后计算“ md5(salt [b]。try[0])”,与条目B比较等等。现在我n要做的工作n很多,文件中包含的用户名和密码的数量是多少。

要了解第二个,您必须了解什么是彩虹表。彩虹表是大量常用密码的预先计算哈希值。再次想象一下没有盐的密码文件。我要做的就是遍历文件的每一行,取出哈希密码,然后在彩虹表中查找它。我永远不必计算单个哈希。如果查找比哈希函数(可能是哈希函数)快得多,这将大大加快文件破解速度。

但是,如果密码文件被添加了盐,那么彩虹表将必须包含预先隐藏的“盐。密码”。如果盐足够随机,则极不可能。我常用的,预先隐藏的密码列表(彩虹表)中可能会包含诸如“ hello”,“ foobar”和“ qwerty”之类的内容,但不会包含诸如“ jX95psDZhello”之类的内容,或者预先计算了“ LPgB0sdgxfoobar”或“ dZVUABJtqwerty”。那将使彩虹桌子变得过大。

因此,盐会使攻击者恢复到每行尝试一次计算,再加上足够长,足够随机的密码,(通常来说)是无法破解的。


15
我不确定我的回答是什么意思?
罗斯,

2
埃里克森(Erickson),我认为编辑令人困惑-我认为大多数人都不认为彩虹表攻击是一种字典攻击。让我知道您认为我的回答是否使您感到困惑,我将尽力予以纠正。
罗斯,

我希望能多给一个赞!特别是对于第一段。这一个总结一下所有恕我直言
塞萨尔

5
我知道这很旧,但是您对Rainbow表的描述不正确。您正在描述哈希表。有关彩虹表,请参见security.stackexchange.com/questions/379/…。哈希表具有从密码到哈希的一对一映射(如您所述),但是rainbow表需要还原功能,该函数将哈希转换回纯文本,然后重新哈希数千次,仅存储初始明文和最终哈希。搜索在计算上比哈希表更长,但是每个哈希“捕获”许多明文。
Mark Fisher

1
这个答案错过了一个事实,即不使用盐(绑定到为特定用户创建密码哈希)也会暴露重复的密码,即使在存储这些密码的多个表上也是如此。至少,您将能够识别一个人重复使用的密码,但更糟糕的是,您还将在不同的数据库上识别不同的人使用的密码。
Maarten Bodewes

119

其他答案似乎并没有解决您对该主题的误解,因此请按以下步骤进行:

盐的两种不同用途

我看过许多教程建议将盐用于以下用途:

$hash = md5($salt.$password)

[...]

我见过的另一种用法是在我的linux系统上。在/ etc / shadow中,哈希密码实际上与salt存储在一起。

始终必须使用密码来存储盐,因为为了验证用户针对您的密码数据库输入的内容,您必须将输入与盐组合起来,对其进行哈希处理并将其与存储的哈希进行比较。

哈希的安全性

现在,拥有彩虹表的人可以反转哈希并提出输入“ foobar”。

[...]

因为已知te5SBM.7C25fFDu6bIRbX的反向哈希包含“ foo”。

不可能这样反转哈希(至少在理论上是这样)。“ foo”的哈希和“ saltfoo”的哈希没有共同之处。更改加密哈希函数的输入中的偶数位应完全更改输出。

这意味着您不能使用通用密码来构建Rainbow表,然后在以后用一些盐“更新”它。您必须从一开始就考虑盐分。

这就是为什么首先需要彩虹表的全部原因。因为无法从哈希中获取密码,所以您需要预先计算最可能使用的密码的所有哈希,然后将其哈希与它们的哈希进行比较。

盐的质量

但是说 $salt=foo

“富”将是一个非常盐糟糕的选择。通常,您将使用以ASCII编码的随机值。

另外,每个密码都有其自己的名称,与系统上的所有其他名称(希望)不同。这意味着,攻击者已经互相攻击的密码,而不是单独具有希望的一个散列的匹配在她的数据库中的值之一。

攻击

如果黑客以某种方式能够获得此文件,那么我就看不出盐的用途是什么,

始终需要彩虹表攻击/etc/passwd(或使用任何密码数据库),否则如何将彩虹表中的哈希与实际密码的哈希进行比较?

出于目的:假设攻击者想要为100,000个常用英语单词和典型密码(例如“秘密”)建立一个彩虹表。没有盐,她将不得不预先计算100,000个哈希。即使使用2个字符的传统UNIX字符集(每个字符都是64个选择之一[a–zA–Z0–9./]),她仍然必须计算和存储4,096,000,000个散列……这是一个很大的进步。


2
真的很好的答案。它帮助我更好地理解了事情。+1
wcm

如果黑客可以访问盐以及该盐在哈希函数中的使用方式,他们难道不能仅使用它来生成盐腌哈希表并将这些哈希与Rainbow表进行比较吗?
强尼

5
@强尼没有“盐”。重点是每个密码输入的内容都不尽相同。

86

含盐的想法是要使暴力破解比普通的基于字符的密码更难猜测。Rainbow表通常在构建时会考虑到特殊的字符集,并且并不总是包括所有可能的组合(尽管可以)。

因此,良好的盐值应为随机的128位或更长的整数。这就是使彩虹表攻击失败的原因。通过为每个存储的密码使用不同的盐值,您还可以确保为一个特定盐值构建的Rainbow表(例如,如果您是一个具有单个盐值的流行系统,则可能不会出现这种情况)一次输入密码。


1
+1:盐可以是由随机数生成器构建的某些随机字符串的十六进制摘要的一部分。每一位都是随机的。
S.Lott

5
“彩虹表是字典攻击的一种形式,它可以提供一定的速度来节省存储空间。” -实际上,相反,好的彩虹表可以接管GB的存储,以节省重新散列所有可能值的时间。
AviD

2
同意-@erickson,我认为您的编辑在那里错误。彩虹表需要巨大的存储量,但使得它快速获得哈希背后的消息。
卡尔·塞勒堡2009年

3
好吧,你们都是对的。与标准字典攻击相比,彩虹表牺牲了速度以节省存储空间。另一方面,与蛮力攻击相比,彩虹桌使用(很多)空间来提高速度。今天,彩虹表几乎是字典的同义词……
Rasmus Faber

...攻击,但是字典攻击不需要彩虹表。
Rasmus Faber

35

还有一个很好的问题,答案很周到-+1!

我未曾明确提及的一个小问题是,通过在每个密码中添加随机盐,实际上可以保证碰巧选择相同密码的两个用户将产生不同的哈希值。

为什么这很重要?

想象一下美国西北部一家大型软件公司的密码数据库。假设它包含30,000个条目,其中500个具有密码bluescreen。进一步假设,黑客设法通过从用户到IT部门的电子邮件中读取密码来获取该密码。如果密码未加盐,则黑客可以在数据库中找到哈希值,然后只需对其进行模式匹配即可访问其他499个帐户。

为密码加盐可确保500个帐户中的每一个都有唯一的(盐+密码),从而为每个帐户生成不同的哈希,从而将违规行为减少到单个帐户。并且,我们极有希望地希望,任何天真地在电子邮件中写明文密码的用户都无法访问下一操作系统的未记录API。


对于选择不同密码的两个用户,此操作相同,并且很可能他们在数据库中存储了相同的哈希密码。(没用...我知道)
2014年

15

我正在寻找一种应用盐的好方法,并找到了这篇带有示例代码的出色文章:

http://crackstation.net/hashing-security.htm

作者建议每位用户使用随机盐,这样一来,获得盐的访问权就不会使整个哈希表变得容易破解。

要存储密码:

  • 使用CSPRNG生成长随机盐。
  • 将盐添加到密码中,并使用标准的加密哈希函数(例如SHA256)对其进行哈希处理。
  • 将盐和哈希值都保存在用户的数据库记录中。

验证密码:

  • 从数据库中检索用户的盐和哈希值。
  • 将盐添加到给定的密码之前,并使用相同的哈希函数对其进行哈希处理。
  • 将给定密码的哈希值与数据库中的哈希值进行比较。如果它们匹配,则密码正确。否则,密码错误。

3
Hashcat可以使用一台PC每秒尝试将近170亿个咸SHA256哈希。链接文章的作者在“使密码更难破解:慢速哈希函数”标题下讨论了这一点。scrypt,bcrypt和PBKDF2是不错的选择,并且比服务器IMHO上的额外CPU周期还值得。Argon2目前是最先进的技术,但没有像其他产品那样经过实战测试。
kgriffs 2015年

12

盐会使彩虹表攻击失败的原因是,对于n位盐,彩虹表必须比没有盐的表大小大2 ^ n倍。

您使用“ foo”作为盐的示例可能会使彩虹表变大1600万倍。

给定Carl的128位盐示例,这会使表大2 ^ 128倍-现在已经很大了-或换句话说,有人拥有这么大的便携式存储需要多长时间?


8
即使您只使用一个电子来存储一点,任何人都需要相当长的时间才能生产出具有这种容量的便携式存储设备……除非您考虑将太阳系移动通过便携式银河系。
erickson

10

破坏基于哈希的加密的大多数方法都依赖于蛮力攻击。Rainbow攻击本质上是一种更有效的字典攻击,它旨在利用低成本的数字存储来创建可能的大量密码子集到哈希表的映射,并促进反向映射。这种攻击之所以有效,是因为许多密码往往很短或者使用几种基于单词的格式模式中的一种。

在密码包含更多字符且不符合常见的基于单词的格式的情况下,此类攻击无效。一开始使用强密码的用户将不会受到这种攻击。不幸的是,许多人没有选择好的密码。但是有一个折衷,您可以通过向用户添加随机垃圾来改善用户密码。因此,现在,他们的密码可以代替“ hunter2”有效地变为“ hunter2908!fld2R75 {R7 /; 508PEzoz ^ U430”,这是更强大的密码。但是,由于您现在必须存储此附加密码组件,因此会降低更强大的复合密码的有效性。事实证明,这种方案仍然有净收益,因为现在每个密码,即使是弱密码,不再容易受到相同的预先计算的哈希/彩虹表的攻击。相反,每个密码哈希条目仅容易受到唯一哈希表的攻击。

假设您的网站密码强度要求不高。如果您不使用任何密码盐,则所有哈希都容易受到预先计算的哈希表的攻击,那么有权访问您的哈希的人将可以访问大部分用户的密码(但是,许多已使用的易受攻击的密码都是很大的百分比)。如果您使用恒定的密码盐,那么预先计算的哈希表将不再有价值,因此有人将不得不花费时间来为该盐计算自定义哈希表,尽管如此,他们仍可以逐步进行,以计算覆盖更大排列的表问题空间。最易受攻击的密码(例如,基于单词的简单密码,非常短的字母数字密码)将在数小时或数天内被破解,而易受攻击的密码将在数周或数月后被破解。随着时间的流逝,攻击者将获得越来越多的用户访问密码的权限。如果您对每个密码使用唯一的盐,那么访问这些易受攻击的密码中的每个密码将需要几天或几个月的时间。

如您所见,当您从无盐变成恒定盐到独特的盐时,在每一步破解易受攻击的密码的努力都会增加几个数量级。如果不加盐,您的用户密码中最弱的密码就可以轻松访问;如果不加盐,则坚定的攻击者可以访问那些较弱的密码;使用不常见的盐,访问密码的成本就会增加得如此之高,以致只有最确定的攻击者才能获得访问权限一小部分易受攻击的密码,然后付出巨大的代价。

正是这种情况。您永远无法完全保护用户免受密码选择不当的困扰,但是您可以将破坏用户密码的成本提高到使破坏一个用户密码的代价变得过高的程度。


3

加盐的目的之一是打败预先计算的哈希表。如果某人拥有数百万个预先计算的哈希值列表,即使他们知道哈希值和盐值,他们也将无法在表中查找$ 1 $ foo $ te5SBM.7C25fFDu6bIRbX1。他们仍然必须蛮力。

正如Carl S所提到的,另一个目的是使强行使用强制性哈希表变得更加昂贵。(给他们所有不同的盐)

即使盐是公开的,这两个目标仍然可以实现。


1

据我所知,salt旨在使字典攻击更加困难。

众所周知的事实是,许多人将使用通用词作为密码,而不是看似随机的字符串。

因此,黑客可以利用此优势而不是仅仅使用蛮力。他不会查找诸如aaa,aab,aac ...之类的密码,而是使用单词和常用密码(如“环名之主!”))

因此,如果我的密码是Legolas,则黑客可以尝试尝试并通过几次尝试就可以猜到。但是,如果我们对密码加盐并且变成fooLegolas,则哈希将有所不同,因此字典攻击将不会成功。

希望有帮助!


-2

我假设您正在使用PHP --- md5()函数,以及$前置变量---然后,您可以尝试查找本文Shadow Password HOWTO特别是第11段。

另外,您担心使用消息摘要算法,可以尝试使用真正的密码算法,例如mcrypt模块提供的算法,或更强大的消息摘要算法,例如提供mhash模块的算法(sha1,sha256和其他)。

我认为必须使用更强大的消息摘要算法。众所周知,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.