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

时间:2009-01-07 15:55:59

标签: hash cryptography salt rainbowtable

我在理解密码的目的时遇到了一些麻烦。据我所知,主要用途是阻碍彩虹表攻击。但是,我看到实现这一点的方法似乎并没有真正解决问题。

我见过许多教程,建议将盐用作以下内容:

$hash =  md5($salt.$password)

原因是哈希现在不映射到原始密码,而是密码和盐的组合。但请说$salt=foo$password=bar以及$hash=3858f62230ac3c915f300c664312c63f。现在有人用彩虹表可以反转哈希并提出输入“foobar”。然后他们可以尝试所有密码组合(f,fo,foo,... oobar,obar,bar,ar,ar)。获取密码可能需要几毫秒,但其他情况并不多。

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

感谢任何人都能解决这个问题。

编辑:感谢您的帮助。为了总结我的理解,salt使得散列密码更加复杂,从而使得它更不可能存在于预先计算的彩虹表中。我之前误解的是我假设所有哈希都存在彩虹表。

10 个答案:

答案 0 :(得分:230)

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

公共盐有两件事:破解大量密码会更耗时,并且使用彩虹表是不可行的。

要理解第一个,想象一个包含数百个用户名和密码的密码文件。没有盐,我可以计算“md5(attempt [0])”,然后扫描文件以查看该哈希是否出现在任何地方。如果存在盐,那么我必须计算“md5(salt [a] .Try [0])”,与条目A进行比较,然后“md5(salt [b] .Try [0])”,与条目B进行比较现在,我有n次工作要做,其中n是文件中包含的用户名和密码数。

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

但是如果密码文件是盐渍的,那么彩虹表必须包含预先散列的“盐。密码”。如果盐足够随机,这是不太可能的。我可能会在我常用的预先伪装密码(彩虹表)列表中找到“hello”和“foobar”和“qwerty”之类的东西,但我不会有像“jX95psDZhello”这样的东西或者“LPgB0sdgxfoobar”或“dZVUABJtqwerty”预先计算。这会使彩虹表格过大。

因此,盐将攻击者减少到每次尝试一次计算,当与足够长,足够随机的密码相结合时,(一般来说)是不可破解的。

答案 1 :(得分:118)

其他答案似乎没有解决您对该主题的误解,所以这里有:

盐的两种不同用途

  

我见过许多教程,建议将盐用作以下内容:

     

$hash = md5($salt.$password)

     

[...]

     

我见过的其他用途是在我的linux系统上。在/ etc / shadow中,散列密码实际上与salt一起存储。

总是必须使用密码存储salt,因为为了验证用户输入的密码数据库,您必须将输入与salt相结合,哈希并对其进行比较到存储的哈希。

散列的安全性

  

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

     

[...]

     

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

不可能像这样反转哈希(理论上至少)。 “foo”的哈希值和“saltfoo”的哈希值共有 nothing 。更改加密哈希函数输入中的一位应该完全改变输出。

这意味着你不能使用通用密码构建彩虹表,然后用一些盐“更新”它。你必须从头开始考虑盐。

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

盐的质量

  

但请说$salt=foo

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

此外,每个密码都有自己的盐,与系统中的所有其他盐不同(希望如此)。这意味着,攻击者必须单独攻击每个密码,而不是希望哈希的一个与她的数据库中的某个值匹配。

攻击

  

如果一名黑客以某种方式获得了这个文件,我看不出盐的用途是什么,

彩虹表攻击总是需要/etc/passwd(或者使用任何密码数据库),否则你如何比较彩虹表中的哈希值与实际密码的哈希值?

至于目的:让我们说攻击者想为10万个常用英语单词和典型密码(想想“秘密”)建立一个彩虹表。如果没有盐,她将不得不预先计算100,000个哈希值。即使使用2个字符的传统UNIX盐(每个是64个选项中的一个:[a–zA–Z0–9./]),她也必须计算和存储4,096,000,000个哈希值......这是一个很大的改进。

答案 2 :(得分:87)

使用salt的想法是使用暴力破解比使用普通的基于字符的密码更难。彩虹表通常是以特殊字符集为基础构建的,并不总是包含所有可能的组合(尽管它们可以)。

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

答案 3 :(得分:35)

又一个很棒的问题,有许多非常深思熟虑的答案 - 对于+1来说!

我没有明确提到的一个小问题是,通过在每个密码中添加一个随机盐,您几乎可以保证两个碰巧选择相同密码的用户会产生不同的哈希值。 /强>

为什么这很重要?

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

保存密码可确保500个帐户中的每个帐户都具有唯一的(salt +密码),为每个帐户生成不同的哈希值,从而减少对单个帐户的破坏。我们希望,在任何可能的情况下,任何天真的足以在电子邮件中写入明文密码的用户都无权访问下一个操作系统的未记录的API。

答案 4 :(得分:15)

我正在寻找一种应用盐的好方法,并找到了这篇包含示例代码的优秀文章:

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

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

  

存储密码:

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

验证密码:

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

答案 5 :(得分:12)

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

使用'foo'作为盐的例子可以使彩虹表大1600万倍。

考虑到Carl的128位盐的例子,这使得这个表大2倍128倍 - 现在这个很大 - 或换句话说,在有人拥有大容量的便携式存储器之前多久?

答案 6 :(得分:10)

打破基于散列的加密的大多数方法都依赖于暴力攻击。彩虹攻击本质上是一种更有效的字典攻击,它旨在使用低成本的数字存储来创建可能的密码到哈希的大量子集的映射,并促进反向映射。这种攻击是有效的,因为许多密码往往相当短或使用少数几种基于单词的格式之一。

在密码包含更多字符且不符合基于常用字词的格式的情况下,此类攻击无效。具有强密码的用户将不会受到这种攻击风格的攻击。不幸的是,很多人都没有选择好的密码。但是有一个妥协,你可以通过添加随机垃圾来改善用户的密码。所以现在,而不是“hunter2”他们的密码可以有效地变成“hunter2908!fld2R75 {R7 /; 508PEzoz ^ U430”,这是一个更强大的密码。但是,因为您现在必须存储此附加密码组件,这会降低更强复合密码的有效性。事实证明,这样的方案仍有净利益,因为现在每个密码,即使是弱密码,也不再容易受到相同的预先计算的散列/彩虹表的影响。相反,每个密码哈希条目仅容易受到唯一哈希表的攻击。<​​/ p>

假设您的网站密码强度要求较低。如果您没有使用密码盐,那么您的哈希很容易受到预先计算的哈希表的影响,那么有权访问您的哈希的人就可以访问大部分用户的密码(但是许多人使用易受攻击的密码,这将是一个很大比例)。如果使用常量密码salt,则预先计算的哈希表不再有价值,因此有人必须花时间为该盐计算自定义哈希表,他们可以逐步增加,计算表覆盖更大的排列问题空间。最易受攻击的密码(例如简单的基于单词的密码,非常短的字母数字密码)将在数小时或数天内被破解,较不易受攻击的密码将在几周或几个月后被破解。随着时间的推移,攻击者将获得越来越多的用户访问密码的权限。如果您为每个密码使用唯一的盐,则需要数天或数月才能访问这些易受攻击的密码。

正如您所看到的,当您从无盐升级到恒定的盐到独特的盐时,您会在每一步中增加几个数量级的力量来破解易受攻击的密码。如果没有盐,用户密码中最弱的密码就可以轻易访问,并且持久的盐可以让坚定的攻击者访问这些弱密码,使用独特的盐可以提高访问密码的成本,只有最坚定的攻击者才能访问密码一小部分易受攻击的密码,然后费用很高。

正是这种情况正是如此。您永远无法完全保护用户免受不良密码选择的影响,但您可以将损害用户密码的成本提高到甚至使一个用户的密码变得非常昂贵的程度。

答案 7 :(得分:3)

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

另一个目的,正如Carl S所提到的那样,是为了使一个哈希列表更加昂贵。 (给他们所有不同的盐)

即使盐是公开的,这两个目标仍然有效。

答案 8 :(得分:1)

据我所知,盐的目的是使字典攻击更难。

众所周知,很多人会使用常用词来代替看似随意的字符串。

因此,黑客可以利用这个优势而不是仅使用蛮力。他不会寻找像aaa,aab,aac这样的密码......而是使用单词和常用密码(比如戒指名称的主人!))

因此,如果我的密码是Legolas,黑客可以尝试这一点,并以“少量”尝试猜测它。但是,如果我们将密码加密并且它变为fooLegolas,则散列将不同,因此字典攻击将失败。

希望有所帮助!

答案 9 :(得分:-2)

我假设您使用的是PHP --- md5()函数,并且$前置变量---那么,您可以尝试查看这篇文章Shadow Password HOWTO特别是第11段。

此外,您害怕使用消息摘要算法,您可以尝试真正的密码算法,例如mcrypt模块提供的算法,或更强大的消息摘要算法,例如提供{ {3}}模块(sha1,sha256和其他)。

我认为更强大的消息摘要算法是必须的。众所周知,MD5和SHA1存在碰撞问题。