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

我不太明白盐对密码的作用。据我所知,它的主要用途是阻止彩虹桌的攻击。然而,我所看到的实现这一点的方法似乎并没有真正使问题变得更难。

我看过很多教程,建议盐可以这样使用:

$hash =  md5($salt.$password)

原因是哈希现在映射的不是原来的密码,而是密码和盐的组合。但是说$salt=foo$password=bar$hash=3858f62230ac3c915f300c664312c63f。现在有一张彩虹表的人可以反向哈希,得到输入“foobar”。然后他们可以尝试所有的密码组合(f, fo, foo,…)Oobar, obar, bar, ar)获取密码可能还需要几毫秒的时间,但仅此而已。

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

感谢大家对这件事的解释。

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

78438 次浏览

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

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

盐的一个目的是打败预先计算的哈希表。如果某人有一个包含数百万预计算哈希值的列表,他们将无法查找$1$foo$te5SBM。7C25fFDu6bIRbX1在表中尽管他们知道哈希和盐。他们还是要用蛮力。

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

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

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

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

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

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

希望有帮助!

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

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

以卡尔的128位盐为例,这使表变大了2^128倍,这很大了,换句话说,要多久才会有人有这么大的便携式存储器?

我假设你正在使用PHP——md5()函数,和$前面的变量——然后,你可以试着看看这篇文章影子密码HOWTO特别是第11段。

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

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

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

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

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

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

但是如果密码文件被加了盐,那么彩虹表就必须包含“salt”。pre-hashed密码”。如果盐是完全随机的,这是不太可能的。在我的常用预哈希密码列表(彩虹表)中,我可能会有“hello”、“foobar”和“qwerty”这样的东西,但我不会预先计算“jX95psDZhello”或“LPgB0sdgxfoobar”或“dZVUABJtqwerty”这样的东西。这将使彩虹桌大得令人望而却步。

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

其他答案似乎并没有解决你对这个话题的误解,所以下面是:

盐的两种不同用途

我看过很多教程,建议盐可以这样使用:

$hash = md5($salt.$password)

[…]

我看到的另一种用法是在我的linux系统上。在/etc/shadow中,散列密码实际上与salt一起存储。

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

哈希的安全性

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

[…]

因为te5SBM的反向哈希。7C25fFDu6bIRbX已知包含“;food &;”。

这样反转哈希是不可能的(至少在理论上是这样)。“;food "“saltfood”的散列;共有没有什么。即使在加密哈希函数的输入中改变一个比特,也会完全改变输出。

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

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

盐的质量

但是说$salt=foo

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

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

这次袭击

如果黑客以某种方式拿到了这份文件,我不明白盐有什么用,

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

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

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

如果密码包含更多字符,且不符合常见的基于单词的格式,这种攻击是无效的。一开始就拥有强密码的用户不会容易受到这种类型的攻击。不幸的是,很多人都没有选择好的密码。但也有一种折衷方法,你可以通过添加随机垃圾来改进用户的密码。所以现在,他们的密码可以变成“hunter2908!fld2R75{R7/;508PEzoz^U430”,而不是“hunter2”,这是一个更强的密码。但是,由于现在必须存储这个额外的密码组件,这降低了更强的组合密码的有效性。事实证明,这样的方案仍然有一个净好处,因为现在每个密码,即使是最弱的密码,都不再容易受到相同的预先计算哈希/彩虹表的攻击。相反,每个密码哈希条目只容易受到唯一哈希表的攻击。

假设您有一个对密码强度要求较低的站点。如果你完全不使用密码盐,你的哈希表很容易受到预先计算的哈希表的攻击,那么访问你哈希表的人就可以访问你大部分用户的密码(不管有多少人使用了易受攻击的密码,这将是一个很大的比例)。如果你使用一个常量密码盐,那么预先计算的哈希表就不再有价值了,所以有人将不得不花时间为这个盐计算一个自定义哈希表,尽管他们可以增量地这样做,计算的表覆盖了问题空间的更大排列。最脆弱的密码(例如简单的基于单词的密码,非常短的字母数字密码)会在几小时或几天内被破解,不那么脆弱的密码会在几周或几个月后被破解。随着时间的推移,攻击者将获得越来越多用户的密码。如果您对每个密码都使用唯一的salt,那么将需要几天或几个月才能访问每个易受攻击的密码。

正如您所看到的,当您从无盐到常量盐再到唯一盐时,每一步都要增加几个数量级的工作量来破解易受攻击的密码。如果没有盐,用户最弱的密码就很容易被访问,如果盐不变,那些弱密码就会被坚定的攻击者访问,如果盐唯一,访问密码的成本就会非常高,只有最坚定的攻击者才能访问一小部分易受攻击的密码,而且代价也很大。

这正是现在的情况。您永远无法完全保护用户不受糟糕密码选择的影响,但您可以提高泄露用户密码的成本,使泄露一个用户密码的代价变得高昂。

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

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

为什么这很重要?

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

加密密码可以确保500个帐户中的每个帐户都有唯一的(salt+密码),为每个帐户生成不同的散列,从而将漏洞减少到单个帐户。让我们希望(尽管可能性不大),任何天真到在电子邮件消息中编写明文密码的用户都无法访问下一个操作系统的未记录的API。

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

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

作者建议对每个用户使用随机salt,这样访问salt就不会使整个哈希列表容易被破解。

存储密码:

  • 使用CSPRNG生成一个长随机盐。
  • 将salt前置到密码并使用标准哈希 加密哈希函数,如SHA256。李< / >
  • 在用户的数据库记录中保存盐和散列。

验证密码:

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