我在理解盐密封的目的时遇到了一些麻烦.据我所知,主要用途是阻碍彩虹表攻击.但是,我看到实现这一点的方法似乎并没有真正解决问题.
我见过许多教程,建议将盐用作以下内容:
$hash = md5($salt.$password)
原因是哈希现在不映射到原始密码,而是密码和盐的组合.但是说$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使得散列密码更加复杂,从而使得它更不可能存在于预先计算的彩虹表中.我之前误解的是,我假设所有哈希都存在彩虹表.
破解单个密码时,公共盐不会使字典攻击变得更难.正如您所指出的,攻击者可以访问散列密码和盐,因此在运行字典攻击时,她可以在尝试破解密码时简单地使用已知的盐.
公共盐可以做两件事:破解大量密码会更加耗时,并且使用彩虹表是不可行的.
要理解第一个,想象一个包含数百个用户名和密码的密码文件.没有盐,我可以计算"md5(attempt [0])",然后扫描文件以查看该哈希是否出现在任何地方.如果存在盐,那么我必须计算"md5(salt [a] .Try [0])",与条目A进行比较,然后"md5(salt [b] .Try [0])",与条目B进行比较等等.现在我有n
很多工作要做,n
文件中包含的用户名和密码的数量在哪里.
要理解第二个,你必须了解彩虹表是什么.彩虹表是常用密码的预先计算的散列的大列表.想象一下没有盐的密码文件.我所要做的就是遍历文件的每一行,取出哈希密码,然后在彩虹表中查找.我永远不必计算单个哈希.如果查找比哈希函数(它可能是)快得多,这将大大加快破解文件的速度.
但是如果密码文件是盐渍的,那么彩虹表必须包含预先散列的"盐.密码".如果盐足够随机,这是不太可能的.我可能会在我常用的预先伪装密码(彩虹表)列表中找到"hello"和"foobar"和"qwerty"之类的东西,但我不会有像"jX95psDZhello"这样的东西或者"LPgB0sdgxfoobar"或"dZVUABJtqwerty"预先计算.这会使彩虹表格过大.
因此,盐将攻击者减少到每次尝试一次计算,当与足够长,足够随机的密码相结合时,(通常来说)是不可破解的.
其他答案似乎并没有解决你对这个话题的误解,所以这里有:
我见过许多教程,建议将盐用作以下内容:
$hash = md5($salt.$password)
[...]
我见过的其他用途是在我的linux系统上.在/ etc/shadow中,散列密码实际上与salt一起存储.
您始终必须使用密码存储salt,因为为了验证用户对密码数据库输入的内容,您必须将输入与salt组合,将其哈希并将其与存储的哈希进行比较.
现在有人用彩虹表可以反转哈希并提出输入"foobar".
[...]
因为已知te5SBM.7C25fFDu6bIRbX的反向散列包含"foo".
这样的哈希是不可能的(理论上至少是这样)."foo"的散列和"saltfoo"的散列没有任何共同之处.在加密散列函数的输入中甚至改变一位应该完全改变输出.
这意味着你不能使用通用密码构建彩虹表,然后用一些盐"更新"它.你必须从一开始就考虑盐.
这就是为什么你需要一张彩虹桌的原因.因为您无法从哈希中获取密码,所以您预先计算最可能使用的密码的所有哈希值,然后将哈希值与哈希值进行比较.
但是说
$salt=foo
"foo"将是一种极其糟糕的盐选择.通常,您将使用以ASCII编码的随机值.
此外,每个密码都有自己的盐,与系统中的所有其他盐不同(希望如此).这意味着,攻击者必须单独攻击每个密码,而不是希望其中一个哈希值与其数据库中的某个值匹配.
如果一个黑客以某种方式能够得到这个文件,我不知道盐的用途是什么,
彩虹表攻击总是需要/etc/passwd
(或者使用任何密码数据库),或者你如何比较彩虹表中的哈希值与实际密码的哈希值?
至于目的:让我们说攻击者想为10万个常用英语单词和典型密码(想想"秘密")建立一个彩虹表.如果没有盐,她将不得不预先计算100,000个哈希值.即使使用2个字符的传统UNIX盐(每个都是64个选项中的一个[a–zA–Z0–9./]
),她也必须计算并存储4,096,000,000个哈希值......这是一个很大的改进.
使用salt的想法是使用暴力来比用普通的基于字符的密码更难猜测.彩虹表通常以特殊字符集为基础构建,并不总是包含所有可能的组合(尽管它们可以).
因此,一个好的盐值将是一个随机的128位或更长的整数.这就是彩虹表攻击失败的原因.通过为每个存储的密码使用不同的salt值,您还可以确保为一个特定的salt值构建彩虹表(如果您是具有单个salt值的流行系统,则可能是这种情况)并不能让您访问所有密码密码一次.
还有一个很好的问题,有很多非常深思熟虑的答案 - 对于+1来说!
我没有明确提到的一个小问题是,通过在每个密码中添加一个随机盐,您几乎可以保证两个碰巧选择相同密码的用户会产生不同的哈希值.
想象一下美国西北部一家大型软件公司的密码数据库.假设它包含30,000个条目,其中500个具有密码bluescreen.进一步假设黑客设法获取此密码,例如通过从用户到IT部门的电子邮件中读取密码.如果密码是未加密的,则黑客可以在数据库中找到散列值,然后只需对其进行模式匹配即可访问其他499个帐户.
对密码进行腌制可确保500个帐户中的每个帐户都具有唯一的(salt +密码),为每个帐户生成不同的哈希值,从而减少对单个帐户的破坏.并且我们希望,在任何可能的情况下,任何天真的足以在电子邮件消息中写入明文密码的用户都无法访问下一个操作系统的未记录的API.
我正在寻找一种很好的方法来应用盐,并找到了这篇包含示例代码的优秀文章:
http://crackstation.net/hashing-security.htm
作者建议每个用户使用随机盐,这样获得盐的访问权限就不会使整个哈希列表容易破解.
存储密码:
使用CSPRNG生成长的随机盐.
将salt添加到密码中,并使用标准加密哈希函数(如SHA256)对其进行哈希处理.
将salt和hash都保存在用户的数据库记录中.
验证密码:
从数据库中检索用户的salt和hash.
将salt添加到给定密码并使用相同的哈希函数对其进行哈希处理.
将给定密码的哈希值与数据库中的哈希值进行比较.如果匹配,则密码正确.否则,密码不正确.
盐可以使彩虹表攻击失败的原因是对于n位盐,彩虹表必须比没有盐的表大小大2 ^ n倍.
你使用'foo'作为盐的例子可以使彩虹表大1600万倍.
鉴于卡尔的128位盐的例子,这使得表大2倍128倍 - 现在这个很大 - 或换句话说,多久以前有人拥有那么大的便携式存储?
打破基于散列的加密的大多数方法都依赖于暴力攻击.彩虹攻击本质上是一种更有效的字典攻击,它旨在使用低成本的数字存储来创建可能的密码到哈希的大量子集的映射,并促进反向映射.这种攻击有效,因为许多密码往往相当短或使用少数几种基于单词的格式之一.
在密码包含更多字符且不符合常见的基于字的格式的情况下,此类攻击无效.具有强密码的用户将不会受到这种攻击风格的攻击.不幸的是,很多人都没有选择好的密码.但是有一个妥协,你可以通过添加随机垃圾来改善用户的密码.所以现在,而不是"hunter2"他们的密码可以有效地变成"hunter2908!fld2R75 {R7 /; 508PEzoz ^ U430",这是一个更强大的密码.但是,因为您现在必须存储此附加密码组件,这会降低更强复合密码的有效性.事实证明,从现在每个密码,即使是弱密码,这个方案仍然有净收益,不再容易受到相同的预先计算的哈希/彩虹表的影响.相反,每个密码哈希条目仅容易受到唯一哈希表的攻击.
假设您的网站密码强度要求较低.如果您没有使用密码盐,那么您的哈希很容易受到预先计算的哈希表的影响,那么有权访问您的哈希的人就可以访问大部分用户的密码(但是许多人使用易受攻击的密码,这将是一个很大比例).如果使用常量密码salt,则预先计算的哈希表不再有价值,因此有人必须花时间为该盐计算自定义哈希表,他们可以逐步增加,计算表覆盖更大的排列问题空间.最易受攻击的密码(例如简单的基于单词的密码,非常短的字母数字密码)将在数小时或数天内被破解,较少易受攻击的密码将在几周或几个月后被破解.随着时间的推移,攻击者将获得越来越多的用户访问密码的权限.如果您为每个密码使用唯一的盐,则需要数天或数月才能访问每个易受攻击的密码.
正如您所看到的,当您从无盐升级到恒定盐到独特的盐时,您需要增加几个数量级的力量,以便在每个步骤中破解易受攻击的密码.如果没有盐,用户密码中最弱的密码就可以轻易访问,并且持久的盐可以让坚定的攻击者访问这些弱密码,使用独特的盐可以提高访问密码的成本,只有最坚定的攻击者才能访问密码一小部分易受攻击的密码,然后费用很高.
正是这种情况正是如此.您永远无法完全保护用户免受糟糕的密码选择,但您可以将损害用户密码的成本提高到甚至使一个用户的密码变得非常昂贵的程度.