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

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

$hash =  md5($salt.$password)

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

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

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

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


当前回答

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

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

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

其他回答

我假设您正在使用PHP——md5()函数和$前面的变量——那么,您可以尝试查看本文的影子密码HOWTO特别是第11段。

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

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

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

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

To understand the first one, imagine a single password file that contains hundreds of usernames and passwords. Without a salt, I could compute "md5(attempt[0])", and then scan through the file to see if that hash shows up anywhere. If salts are present, then I have to compute "md5(salt[a] . attempt[0])", compare against entry A, then "md5(salt[b] . attempt[0])", compare against entry B, etc. Now I have n times as much work to do, where n is the number of usernames and passwords contained in the file.

To understand the second one, you have to understand what a rainbow table is. A rainbow table is a large list of pre-computed hashes for commonly-used passwords. Imagine again the password file without salts. All I have to do is go through each line of the file, pull out the hashed password, and look it up in the rainbow table. I never have to compute a single hash. If the look-up is considerably faster than the hash function (which it probably is), this will considerably speed up cracking the file.

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

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

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

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

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

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

盐的两种不同用途

我看过很多教程,建议盐可以这样使用: $hash = md5($salt.$password) […] 我看到的另一种用法是在我的linux系统上。在/etc/shadow中,散列密码实际上与salt一起存储。

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

哈希的安全性

现在有一张彩虹表的人可以反向哈希,得到输入“foobar”。 […] 因为te5SBM的反向哈希。已知7C25fFDu6bIRbX包含“foo”。

这样反转哈希是不可能的(至少在理论上是这样)。“foo”的哈希和“saltfoo”的哈希没有任何共同之处。即使在加密哈希函数的输入中改变一个比特,也会完全改变输出。

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

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

盐的质量

但是输入$salt=foo

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

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

这次袭击

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

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

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

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

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

为什么这很重要?

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

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