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

Posted

技术标签:

【中文标题】密码盐如何帮助抵御彩虹表攻击?【英文标题】:How does password salt help against a rainbow table attack? 【发布时间】:2010-09-30 01:38:27 【问题描述】:

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

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

$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”。

感谢任何人对此提供的任何启发。

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

【问题讨论】:

另见***.com/questions/213380/… 另见:***.com/questions/1645161/… 另外,在此处更新 - 使用 md5 散列不再是最佳实践。 ***.com/questions/12724935/salt-and-passwords 感谢您的编辑。我有同样的疑问,现在已经澄清了。因此,“Salt”的真正意义在于首先使 Rainbow 表极不可能包含掺假(加盐)密码的哈希值。 :D 【参考方案1】:

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

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

【讨论】:

+1:Salt 可以是随机数生成器构建的一些随机字符串的十六进制摘要的一部分。每个位都是随机的。 “彩虹表是一种字典攻击形式,它放弃了一些速度以节省存储空间。” - 实际上相反,一个好的彩虹表可以占用 GB 来存储,以节省重新散列所有可能值的时间。 同意 - @erickson,我认为你的编辑是错误的。彩虹表需要 大量 存储空间,但可以快速获取散列背后的消息。 嗯,你们都是对的。与标准字典攻击相比,彩虹表牺牲了速度以节省存储空间。另一方面,与蛮力攻击相比,彩虹桌使用(大量)空间来获得速度。今天,彩虹表几乎是字典的代名词...... ... 攻击,但字典攻击不需要彩虹表。【参考方案2】:

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

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

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

【讨论】:

【参考方案3】:

据我所知,加盐是为了让字典攻击更难。

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

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

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

希望有帮助!

【讨论】:

【参考方案4】:

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

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

考虑到 Carl 的 128 位 salt 示例,这会使表变大 2^128 倍 - 现在已经很大了 - 或者换句话说,多久才有人拥有这么大的便携式存储空间?

【讨论】:

即使你使用单个电子来存储一点点,也需要很长时间才能生产出具有这种容量的便携式存储设备......除非你考虑到太阳系在银河系中移动是便携式的。 【参考方案5】:

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

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

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

【讨论】:

【参考方案6】:

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

公共盐有两个作用:破解大量密码列表更加耗时,并且无法使用彩虹表。

要理解第一个,想象一个包含数百个用户名和密码的密码文件。如果没有盐,我可以计算“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 将攻击者减少到每次尝试每行计算一次,当加上足够长、足够随机的密码时,它(一般来说)是不可破解的。

【讨论】:

我不确定我在回答中是否暗示他们是? erickson,我认为编辑令人困惑——我不认为大多数人认为彩虹表攻击是一种字典攻击。如果您认为我的回答中存在令人困惑的具体内容,请告诉我,我会尽力纠正。 我希望一个可以给超过一个赞成票!尤其是第一段。那一个总结了所有恕我直言 我知道这是旧的,但您对彩虹表的描述不正确。您正在描述哈希表。彩虹桌请见security.stackexchange.com/questions/379/…。哈希表具有密码到哈希的 1 对 1 映射(如您所描述的),但彩虹表需要一个归约函数,将哈希转换回纯文本,然后重新哈希数千次,仅存储初始明文和最终哈希。搜索的计算时间比哈希表长,但每个哈希“捕获”许多明文。 这个答案忽略了一个事实,即不使用盐(绑定到为特定用户创建密码哈希)也会暴露重复的密码,即使在存储这些密码的多个表中也是如此。至少您可以识别一个人重复使用的密码,但更糟糕的是,您还可以识别不同人在不同数据库中使用的密码。【参考方案7】:

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

盐的两种不同用途

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

$hash = md5($salt.$password)

[...]

我看到的另一个用途是在我的 linux 系统上。在 /etc/shadow 中,哈希密码实际上与 salt 一起存储。

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

哈希的安全性

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

[...]

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

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

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

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

盐的质量

但是说$salt=foo

"foo" 将是一个非常糟糕的盐选择。通常你会使用一个随机值,用 ASCII 编码。

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

攻击

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

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

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

【讨论】:

非常好的答案。它帮助我更好地理解事物。 +1 如果黑客可以访问盐以及它是如何在散列函数中使用的,他们就不能用它来生成一个加盐散列表并将这些散列与彩虹表进行比较吗? @Jonny 没有“盐”。关键是每个密码输入的盐都是不同的。【参考方案8】:

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

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

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

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

正是这种情况。您永远无法完全保护用户免受错误密码选择的影响,但您可以将泄露用户密码的成本提高到甚至让泄露一个用户密码的成本高得令人望而却步的程度。

【讨论】:

【参考方案9】:

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

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

为什么这很重要?

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

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

【讨论】:

对于选择不同密码的两个用户来说相同,很可能他们在数据库中存储了相同的哈希密码。 (没用……我知道)【参考方案10】:

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

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

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

存储密码:

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

验证密码:

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

【讨论】:

Hashcat 可以使用单台 PC 每秒尝试近 170 亿次加盐 SHA256 哈希。链接文章的作者在“使密码破解更难:慢散列函数”标题下谈到了这一点。 scrypt、bcrypt 和 PBKDF2 是不错的选择,而且非常值得服务器恕我直言额外的 CPU 周期。 Argon2 目前是最先进的,但不像其他人那样经过实战考验。

以上是关于密码盐如何帮助抵御彩虹表攻击?的主要内容,如果未能解决你的问题,请参考以下文章

如何安全的存储用户密码?

bcrypt 哈希究竟如何防止彩虹表查找?

如何在 .NET WCF 中保护 HTTP JSON Web 服务

如何抵御社工库类的黑客攻击?在明文密码已泄露的情况下保护自己?

你在哪里存放你的盐串?

生成具有恒定轨道的盐