关于哈希:密码盐如何帮助抵御彩虹表攻击?

How does password salt help against a rainbow table attack?

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

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

1
$hash =  md5($salt.$password)

原因是散列现在映射到的不是原始密码,而是密码和salt的组合。但是,比如$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。如果一个黑客不知何故能够得到这个文件,我不知道盐有什么作用,因为已知te5SBM.7C25fFDu6bIRbX的反向散列包含"foo"。

谢谢你给我的任何启示。

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


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

公共盐有两个作用:使破解大量密码更加耗时,并且使使用彩虹表变得不可行。

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

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

但是如果密码文件是salt,那么彩虹表就必须包含"salt"。密码"预先散列。如果盐足够随机,这是非常不可能的。我可能会在常用的预哈希密码列表(彩虹表)中列出"hello"、"foobar"和"qwerty",但我不会预先计算"jx95psdhello"、"lpgb0sdgxfoobar"或"dzvuabjtqwerty"。这将使彩虹桌显得异常大。

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


其他答案似乎无法解决您对该主题的误解,因此,请注意:

盐的两种不同用途

I've seen many tutorials suggesting that the salt be used as the following:

$hash = md5($salt.$password)

[...]

The other use I've seen is on my linux system. In the /etc/shadow the hashed passwords are actually stored with the salt.

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

哈希的安全性

Now somebody with a rainbow table could reverse the hash and come up with the input"foobar".

[...]

since the reverse hash of te5SBM.7C25fFDu6bIRbX is known to contain"foo".

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

这意味着您不能用常用密码构建彩虹表,然后用一些盐"更新"它。你必须从一开始就把盐考虑进去。

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

盐的质量

But say $salt=foo

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

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

攻击

If a hacker somehow were able to get his hands on this file, I don't see what purpose the salt serves,

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

至于目的:假设攻击者想要为100000个常用英语单词和典型密码构建一个彩虹表(想想"秘密")。如果没有盐,她必须预先计算100000哈希。即使使用传统的2个字符的unix salt(每个字符是64种选择之一:[a–zA–Z0–9./]),她也必须计算和存储4096亿个哈希…相当不错。


使用salt的想法是使用蛮力比普通的基于字符的密码更难猜测。彩虹表通常是建立在一个特殊的字符集的思想,并不总是包括所有可能的组合(尽管他们可以)。

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


还有一个很好的问题,有很多很贴心的答案,+1比0!

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

为什么这很重要?

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

对密码进行salt可以确保500个帐户中的每个帐户都有一个唯一的(salt+密码),从而为每个帐户生成不同的哈希,从而减少对单个帐户的破坏。我们希望,无论如何,任何天真地在电子邮件中编写纯文本密码的用户都不能访问下一个操作系统的未记录API。


我正在寻找一种很好的方法来施用盐,发现这篇优秀的文章带有样本代码:

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

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

To Store a Password:

  • Generate a long random salt using a CSPRNG.
  • Prepend the salt to the password and hash it with a standard
    cryptographic hash function such as SHA256.
  • Save both the salt and the hash in the user's database record.

To Validate a Password :

  • Retrieve the user's salt and hash from the database.
  • Prepend the salt to the given password and hash it using the same hash function.
  • Compare the hash of the given password with the hash from the database. If they
    match, the password is correct. Otherwise, the password is incorrect.


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

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

以卡尔的128位盐为例,这使得表大了2^128倍——现在大了——或者换一种方式说,还有多长时间人们才能拥有这么大的便携式存储空间?


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

这种攻击在密码包含更多字符且不符合通用的基于单词的格式的情况下是无效的。以强密码开始的用户不会受到这种攻击。不幸的是,许多人不会选择好的密码。但是有一个折衷办法,你可以通过添加随机垃圾来改进用户的密码。所以现在,他们的密码不是"hunter2",而是"hunter2908"!fld2r75 r7/;508pezoz^u430",这是一个更强大的密码。但是,由于现在必须存储这个额外的密码组件,这会降低更强的复合密码的有效性。事实证明,这样的方案仍然有一个好处,因为现在每个密码,即使是弱密码,都不再容易受到相同的预先计算的哈希/彩虹表的攻击。相反,每个密码哈希条目只对一个唯一的哈希表敏感。

假设你有一个弱密码强度要求的站点。如果您在所有哈希表中都不使用密码salt,则容易受到预先计算的哈希表的攻击,因此,有权访问哈希表的人可以访问您的大部分用户的密码(然而,许多人使用的是易受攻击的密码,这将是相当大的百分比)。如果使用常量密码salt,那么预先计算的哈希表就不再有价值了,因此必须有人花时间为该salt计算一个自定义哈希表,但是他们可以增量地计算包含问题空间更大排列的表。最易受攻击的密码(例如简单的基于单词的密码、非常短的字母数字密码)将在数小时或数天内被破解,而不易受攻击的密码将在数周或数月后被破解。随着时间的推移,攻击者将获得越来越多的用户访问密码的权限。如果对每个密码使用唯一的salt,那么访问每个易受攻击的密码需要几天或几个月的时间。

正如您所看到的,当您从无盐升级到恒盐,再升级到独特的盐时,您会在每个步骤中强制增加几个数量级,以破解易受攻击的密码。如果没有盐,用户最脆弱的密码是非常容易访问的,如果使用恒定盐,确定的攻击者就可以访问这些脆弱的密码,使用独特的盐,访问密码的成本会提高到如此之高,只有最确定的攻击者才能访问脆弱密码的一小部分,然后只有在gre时才能访问。费用。

这正是我们要面对的情况。你永远无法完全保护用户不受密码选择不当的影响,但你可以将泄露用户密码的成本提高到一个甚至让一个用户的密码代价高昂的水平。


加盐的一个目的是击败预先计算的哈希表。如果有人有数百万个预先计算的哈希表,即使他们知道哈希表和盐,他们也无法在他们的表中查找$1$foo$te5sbm.7c25ffdu6birbx1。他们还是要蛮力的。

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

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


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

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

所以,黑客可以利用这个优势,而不是仅仅使用暴力。他不会查找AAA、AAB、AAC等密码…但是要使用单词和普通密码(比如戒指之王的名字!;)

所以,如果我的密码是legolas,黑客可以尝试一下,然后通过"几次"尝试来猜测。然而,如果我们对密码加盐,它就变成了愚人的散列,散列将不同,因此字典攻击将不成功。

希望有帮助!


我假设您使用的是php---md5()函数和$befored变量---然后,您可以尝试查看本文的影子密码,特别是第11段。

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

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