237

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

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

$hash =  md5($salt.$password)

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

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

感谢任何人都可以对此有所了解。

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

4

10 回答 10

258

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

公开的盐有两件事:让破解大量密码列表变得更加耗时,并且使得使用彩虹表变得不可行。

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

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

但是如果密码文件是加盐的,那么彩虹表必须包含预先散列的“salt.password”。如果盐足够随机,这不太可能。我的常用预哈希密码列表(彩虹表)中可能会有“hello”、“foobar”和“qwerty”之类的东西,但我不会有“jX95psDZhello”之类的东西或“LPgB0sdgxfoobar”或“dZVUABJtqwerty”预计算。那会使彩虹表大得令人望而却步。

因此,salt 将攻击者减少到每次尝试每行一次计算,当再加上足够长、足够随机的密码时,它(一般来说)是不可破解的。

于 2009-01-07T16:50:10.820 回答
122

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

盐的两种不同用途

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

$hash = md5($salt.$password)

[...]

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

始终必须将盐与密码一起存储,因为为了验证用户在您的密码数据库中输入的内容,您必须将输入与盐结合起来,对其进行散列并将其与存储的散列进行比较。

哈希的安全性

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

[...]

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

不可能像这样反转散列(至少在理论上)。“foo”的哈希值和“saltfoo”的哈希值没有任何共同之处。即使在密码散列函数的输入中更改一位也应该完全改变输出。

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

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

盐的质量

但是说$salt=foo

“foo”将是一个极差的盐选择。通常你会使用一个随机值,用 ASCII 编码。

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

攻击

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

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

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

于 2009-01-07T17:06:20.227 回答
88

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

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

于 2009-01-07T15:59:47.773 回答
37

还有一个很好的问题,有许多非常周到的答案——+1 !

我没有看到明确提到的一个小点是,通过向每个密码添加随机盐,您实际上可以保证碰巧选择相同密码的两个用户会产生不同的哈希值。

为什么这很重要?

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

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

于 2009-01-10T16:30:37.857 回答
15

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

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

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

要存储密码:

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

验证密码:

  • 从数据库中检索用户的盐和哈希。
  • 将盐添加到给定密码并使用相同的散列函数对其进行散列。
  • 将给定密码的哈希值与数据库中的哈希值进行比较。如果它们匹配,则密码正确。否则,密码不正确。
于 2012-07-13T19:18:17.090 回答
12

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

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

鉴于 Carl 的 128 位 salt 示例,这会使表变大 2^128 倍——现在已经很大了——或者换一种说法,人们多久才能拥有这么大的便携式存储空间?

于 2009-01-07T16:11:35.173 回答
10

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

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

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

如您所见,当您从无盐升级到恒定盐再到唯一盐时,您在每一步破解易受攻击的密码的努力都会增加几个数量级。没有盐,您的用户密码中最弱的密码可以轻松访问,使用恒定盐,坚定的攻击者可以访问这些弱密码,使用唯一的盐,访问密码的成本会提高到如此高,以至于只有最坚定的攻击者才能获得访问权限到一小部分易受攻击的密码,然后只付出巨大的代价。

正是这种情况。您永远无法完全保护用户免受错误密码选择的影响,但是您可以将泄露用户密码的成本提高到一个水平,即使泄露一个用户的密码也会非常昂贵。

于 2009-01-08T00:21:31.160 回答
3

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

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

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

于 2009-01-07T16:06:02.300 回答
1

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

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

因此,黑客可以利用这一点而不是仅仅使用蛮力。他不会寻找像 aaa、aab、aac 这样的密码……而是使用单词和常用密码(比如指环王的名字!;))

因此,如果我的密码是 Legolas,黑客可以尝试并通过“几次”尝试来猜测它。但是,如果我们对密码进行加盐,它变成了 fooLegolas,那么哈希值就会不同,因此字典攻击将不成功。

希望有帮助!

于 2009-01-07T16:06:38.320 回答
-2

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

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

我认为更强的消息摘要算法是必须的。已知 MD5 和 SHA1 存在冲突问题。

于 2009-01-07T16:26:09.887 回答