我的理解是随机盐值仅与密码哈希连接。为什么不可以将彩虹表用于密码哈希并忽略已知为随机盐哈希的前X个位?我想让它起作用,目录(LDAP等)必须存储特定于每个用户的盐,或者盐似乎会“丢失”并且永远不会进行身份验证。
#1 楼
通常它是这样的:说您的密码是“棒球”。我可以简单地将其原始存储,但是任何获取我的数据库的人都可以获取密码。因此,我改为在其上进行SHA1哈希,然后得到:
$ echo -n baseball | sha1sum
a2c901c8c6dea98958c219f6f2d038c44dc5d362
从理论上讲,不可能反转SHA1哈希。但是,使用Google对该确切的字符串进行搜索,就可以轻松恢复原始密码。此外,如果数据库中的两个用户使用相同的密码,那么他们将拥有相同的SHA1哈希。如果其中一个密码提示为
try "baseball"
,那么我现在知道两个用户的密码是什么。因此,在对它进行哈希处理之前,我们会在字符串前添加一个唯一的字符串。不是秘密,而是独特的东西。怎么样
WquZ012C
。因此,现在我们对字符串WquZ012Cbaseball
进行哈希处理。这有以下含义:c5e635ec235a51e89f6ed7d4857afe58663d54f5
谷歌搜索该字符串不会显示任何内容(也许此页面除外),所以现在我们来谈谈。如果person2也使用“棒球”作为密码,我们将使用不同的盐并获得不同的哈希值。
当然,要测试您的密码,您必须知道盐是什么。所以我们必须将其存储在某个地方。大多数实现只是使用哈希(通常使用一些定界符)将其添加到此处。如果安装了
openssl
,请尝试以下操作:[tylerl ~]$ openssl passwd -1
Password: baseball
Verifying - Password: baseball
$oaagVya9$NMvf1IyubxEYvrZTRSLgk0
这使用标准
crypt
库为我们提供了哈希值。所以我们的哈希是$oaagVya9$NMvf1IyubxEYvrZTRSLgk0
:实际上是3个部分,由$
分隔。我将用空格替换定界符,以使其在视觉上更清晰:还有很多其他更好的方法,但这是我们的例子。oaagVya9是我们的食盐。
NMvf1IyubxEYvrZTRSLgk0是实际的MD5和,以base64编码。如果我再次运行该过程,则会得到完全不同的哈希值,并带有不同的盐。在此示例中,大约有1014种方法来存储此密码。所有这些都是用于密码“棒球”的:
$oaagVya9$NMvf1IyubxEYvrZTRSLgk0
1 oaagVya9 NMvf1IyubxEYvrZTRSLgk0
但是,如果我故意指定要检查的盐,我会得到我的预期结果: >这就是我要检查密码是否正确的测试。找到为用户存储的哈希,找到保存的盐,使用保存的盐重新运行相同的哈希,检查结果是否与原始哈希匹配。
自己实现
要清楚帖子不是实施指南。不要简单地给MD5加盐并称其为好。在当今的风险环境中,这还远远不够。相反,您将要运行一个迭代过程,该过程将运行哈希函数数千次。这已经在其他地方多次解释过了,所以在这里我不再赘述。
有几个公认的可靠选项可以做到这一点: > crypt:我上面使用的功能是所有Unix / Linux操作系统内置的unix
crypt
密码哈希机制的较旧版本。原始版本(基于DES)非常不安全;甚至不要考虑它。我展示的(基于MD5)更好,但今天仍然不应该使用。以后的版本,包括SHA-256和SHA-512版本,应该是合理的。所有最新的变体都实现多轮哈希。bcrypt:上述
crypt
函数调用的河豚版本。利用了河豚的键设置过程非常昂贵的事实,并采用“ cost”参数来相应地增加键设置时间。PBKDF2:(“基于密码的密钥派生功能版本2”)创建用于从简单密码生成强密码密钥,这是此处列出的唯一实际上具有RFC的功能。运行可配置的回合数,每回合都会散列密码和上一回合的结果。第一轮使用盐。值得注意的是,其最初的目的是创建强密钥,而不是存储密码,但是目标的重叠也使它成为这里值得信赖的解决方案。如果您没有可用的库并被迫从头开始实现某些功能,那么这是最简单,文档最详尽的选择。但是,显然,使用经过严格审查的库始终是最好的。
scrypt:最近引入的系统专门设计为难以在专用硬件上实现。除了需要多轮哈希函数外,scrypt还具有很大的工作内存状态,从而增加了实现的RAM需求。尽管它非常新,而且大多未经验证,但它看起来至少与其他安全性一样,甚至可能是所有安全性中最安全的。
评论
我所见过的关于哈希的最好,最清晰,最完整的解释。我计划在有关安全性的课程中无耻地使用它。
–说唱
2014年2月21日在18:14
@JeffGohlke如果您使用的是8个字符的盐,即62 ^ 8或218万亿种可能的盐。而且,您只想确保对相同的密码不要两次使用相同的盐。因此,不,您实际上不需要担心重复使用盐。
–亚当·香脂
2014年2月21日在20:56
您能否添加关于密钥扩展和使用适当的KDF的最后一段,否则这篇文章将由仅阅读此答案并去做自己的事情的用户创建更多sha1(salt || pwd)方案。我知道这在技术上是题外话,但我们确实需要通过避免不建议直接使用它来与之抗衡。
–托马斯
2014-2-22在0:28
我来到这里,阅读答案,用谷歌搜索c5e635ec235a51e89f6ed7d4857afe58663d54f5,然后再次来到这里! :) +1
– Kenyakorn Ketsombut
2014年2月25日在2:42
也许您应该更新此答案以提及argon2。
–森林
18 Mar 9 '18 at 9:30
#2 楼
从技术上讲,您仍然可以使用彩虹桌攻击盐渍的哈希。但仅在技术上。盐腌哈希可以克服彩虹表攻击,不是通过添加加密魔术来实现的,而只是通过成倍增加成功找到冲突所需的彩虹表的大小。是的,您需要存储盐:)
评论
有人支持,因为这是唯一能真正解释为什么盐腌的哈希对彩虹桌有所帮助的答案。
–nwellnhof
2014年2月23日,20:55
而且它成倍地增加。
–乔纳森·哈特利
2014年2月25日在9:43
表格的大小不会更大。每个用户都需要一个单独的Rainbow表(因为每个用户的密码使用了不同的盐),但是每个用户的大小都相同。无需下载彩虹表来表示字符串的SHA-1哈希,而是创建自己的CYyohYn8MGYk盐化字符串的SHA-1哈希。但是,这将是无用的练习,因为对特定密码的蛮力攻击会更快。盐起作用,不是因为表的大小增加了,而是因为它们使标准的可下载彩虹表无法使用。
– mgr326639
16-10-26在10:08
@ mgr326639-我在回答中没有提到“标准可下载彩虹表”,实际上我不知道是否存在标准。这个问题提到“建立”彩虹桌。您可以拥有一个可以满足整个需求的大表,也可以具有与salts一样多的表,或者根据您的资源或任何其他因素想要的任何逻辑或物理分区方案。
–xkcd
16-10-26在12:16
#3 楼
它不会在哈希之后添加。它是在哈希之前添加的,因此每种盐的哈希都是完全不同的。 />hash abcd = defg
store 123defg (for user with 123 salt) and 456defg (for user with 456 salt)
评论
最后两句话花了我一些时间来解析:-)
–约兰达·鲁伊斯(Yolanda Ruiz)
2014年2月20日在21:49
@YolandaRuiz-试图清理一点
– AJ亨德森
2014年2月20日在22:02
我的大脑有些融化,但是现在我明白了你在这里所做的事情。 ;-)
– SilverlightFox
2014年2月21日在9:45
如果您说“一个用户的密码abcd带有salt 123,另一个用户的密码abcd带有salt 456,这可能会使事情变得更清楚。然后对于第二个示例,添加一行“ store 123ghij and 456klmn”。
–超级猫
2014年2月21日在18:06
#4 楼
对于密码哈希,您需要使用PBKDF2 / RFC2898 / PKCS5v2,Bcrypt或Scrypt之类的东西,所有这些都允许您选择一定数量的迭代(“工作因子”),而不仅仅是一个。例如,PBKDF2在内部使用HMAC键控散列和众所周知的散列算法(通常为SHA-512,SHA-256或SHA-1)进行多次迭代,最好保持成千上万个基本上没有用户抱怨。大量迭代的原因是降低攻击者的速度,从而减少了他们在给定时间段内可以通过的密钥空间,因此他们无法有效地攻击更好的密码。显然,无论是在脱机攻击中,“ password”和“ P @ $$ w0rd”都将被破解。
您是正确的,每一行(用户)都需要自己独特地生成,加密随机长盐。该盐以明文形式存储。
对于PBKDF2,Bcrypt或Scrypt,我还建议将迭代次数(工作因子)也以明文形式存储在数据库中,因此很容易更改(个人而言,我使用了某种程度的随机性)迭代次数-如果总是不同,那么不必担心“哦,不行,微小的更改可能会使所有事情弄糟-永远不要改变管理层或其他开发人员的想法”)
请注意,在使用PBKDF2时对于密码哈希,请不要要求比本地哈希输出大的输出-SHA-1为20字节,SHA-512为64字节。
给出PBKDF2的实际示例两种不同的盐:
(PBKDF2 HMAC密码盐迭代输出字节结果)
2e3259bece6992f012966cbf5803103fdea7957ac20f3ec305d62994a3f4f088f26cc3889053fb59a4e3c282f55e9179695609ee1147cffae1455880993ef874
PBKDF2 HMAC-SZ6512 MyPass L1 64
1018ad648096f7814bc2786972eb4091f6c36761a8262183c24b0f4d34abb48073ed2541ee273220915638b46ec14dfb2b23ad64c4aa12f97158340bdc12fc57
#5 楼
除了tylerl所说的外,还需要强调的是,在现代加密货币中,盐不用于防止彩虹表。没有人真正使用彩虹表。真正的危险是并行化:如果您没有盐,或者只有静态盐,并且我窃取了数百万个哈希的数据库,那么我可以将所有内核扔掉以蛮横地对待,并且每个内核将同时攻击一百万个哈希,因为每当我击中用作密码的任何字符串时,我都会看到一个哈希匹配。因此,我需要耗尽一次搜索空间才能破解一百万个密码。这是一个完全现实的密码泄漏规模,并且是一个诱人的目标,足以在甚至自定义FPGA上抛出几十个GPU。即使我只用尽了搜索空间的底部30%,我仍然会带着大约50万个真实密码走开。这些密码将用于构建我的字典,因此下次有人泄漏哈希数据库时,我将在几小时内破解其中的90%。
如果每个密码都使用自己独特的盐进行哈希处理,那么我将需要分别攻击其中的每一个,因为即使是相同的密码也会存储完全不同的哈希值。这意味着我也许可以使用昂贵的,耗电的GPU / FPGA场来攻击这对高价值目标(例如,如果奥巴马是您的用户,那么获得他的密码仍然值得花钱),但我不会免费提供数十万个密码。如果要获取完整的一百万个密码,则必须进行一百万次完整的蛮力搜索。只要它未被广泛使用,但只有独特的基于哈希的盐才能保护您免受使用大量并行计算功能一次破解所有内容的真正危险。
#6 楼
这样做更加安全,因为当多个人使用相同的密码时,他们将具有不同的哈希值。使用Python的简单实现: salt:
import hashlib
passwordA = '123456'
passwordB = '123456'
hashlib.md5(passwordA).hexdigest()
'e10adc3949ba59abbe56e057f20f883e'
hashlib.md5(passwordB).hexdigest()
'e10adc3949ba59abbe56e057f20f883e'
这是非常简化的版本。您可以在任何需要的地方加盐。在密码的开头/中间/结尾。
盐非常有用,尤其是当您有很多用户时,每个人都有不同的哈希值。现在想象一下,对于数百万个帐户(例如Facebook或Google或Twitter帐户)使用相同密码的可能性。
#7 楼
首先,如果两个用户使用相当弱的密码“棒球”,那么破解一个密码根本不会帮助由于咸化而破解第二个密码。在不加盐的情况下,您以一个价格破解了两个密码。第二,彩虹表包含预先计算的哈希值。因此,破解者可以在具有大量条目的彩虹表中查找“棒球”的哈希值。比计算彩虹表中的gazillion哈希要快得多。而且可以通过盐腌来防止。
现在是重要的一个:有些人的密码很好,有些人的密码不好。如果您有一百万个用户,而三个用户使用相同的密码,则只知道该密码是弱密码。不加盐,您将具有三个相同的哈希。因此,如果有人窃取了您的哈希数据库,他们可以立即查看哪些用户的密码较弱并集中精力破解这些密码。比1keOj29fa0romn更容易破解“棒球”。不加盐,弱密码会脱颖而出。通过撒盐,破解者不知道哪个密码是弱密码,哪些密码很难破解。
#8 楼
如果攻击者拥有密码哈希,则哈希是否加盐只会有不同。没有盐,哈希表可以攻击彩虹表:将密码与哈希表关联的预先计算的字典。 N位的盐增加了Rainbow表的存储需求,并增加了该表的计算时间,为2 ** N。因此,例如,使用32位盐,仅一个彩虹表字典条目(例如,密码passw0rd
)就需要大量GB的存储空间,使用当前的存储硬件,这样的彩虹表非常昂贵。因此,当存在盐时,攻击者将对获得的特定密码散列进行暴力攻击。但是:对于弱密码,将在相对较短的时间内成功进行蛮力攻击。
在彩虹表中找不到足够强的密码。
如果攻击者可以访问哈希,则系统安全性已经受到威胁。 :现代系统和协议不会显示其密码哈希。如果攻击者无法访问密码数据库,则密码也可能以明文形式存储。
如果攻击者必须破坏系统以获取哈希值以从中撤消密码它们,那么唯一对攻击者有价值的密码就是那些可用于攻击者尚无法访问的其他安全域的密码。未重用的密码没有价值(并且肯定比与该帐户相关联的其他敏感信息的价值小)。
假设用户
joewestlake
使用密码god1234
。攻击者使用彩虹表立即将其撤消。 (或者由于密码太糟糕,如果使用哈希攻击,在短短几分钟内使用暴力破解就可以破解了,因为密码太糟糕了。)现在的问题是joewestlake
也将god1234
用于他的Gmail帐户以及在线银行服务,哎呀!现在,攻击者阅读了Joe的电子邮件,并且对Joe有足够的了解,以便他可以在登录Joe的网上银行时轻松回答“您的第一个宠物的名字是什么”的问题。盐的基本原理是它们通过使中等安全性密码更难逆转而在某种程度上保护了用户:可以合理地预期在彩虹表中找到不加盐的密码,但是该密码足够坚固,可以单独对它们进行强行强制需要很长时间。但是盐仅在哈希已被破坏(这已经是严重的安全漏洞)的情况下才提供此好处,并且此好处仅适用于在其他系统中重用其中等安全性密码的那些用户。说乔,而是使用由10个随机字母数字字符和符号组成的密码。这可能仍在彩虹表中,但需要大量工作。因此,即使Joe为Gmail和网上银行使用了相同的密码,由于安全,他还是安全的。饼干可能会持续数小时甚至数天的暴力破解。破解会从同一系统的其他弱口令用户那里产生许多弱口令。攻击者对该收益感到满意并停止破解; Joe的密码永远不会被取消。
此外,如果检测到违规并且建议用户(包括Joe)更改密码,则即使攻击者继续攻击包括Joe的密码在内的整个中等安全性密码空间,Joe也有机会超越攻击者的破解尝试。 。 Joe知道,他在受感染系统上使用的密码与他的Gmail和银行密码完全相同,因此他争先更改其他两个密码。盐在这里有帮助,因为它为重新使用密码的用户节省了更改密码的时间。盐对那些在几分钟之内就能破解很弱的密码的人无济于事,但是需要数小时或数天才能破解的密码用户却有很大的机会。
评论
除了AJ的评论之外,仅对哈希值加盐不足以确保安全的密码存储。诸如bcrypt和scrypt之类的现代密码哈希算法需要大量的CPU和/或内存,这大大降低了攻击者进行猜测的能力。几年前,我写了一系列文章回答您的问题。 blogs.msdn.com/b/ericlippert/archive/tags/salt
是的,盐与哈希一起存储,盐应按用户使用。
盐也可以是全局盐,连接到userID,然后进行哈希处理,以生成用于用户密码哈希的唯一盐。这样,您无需为每个用户存储任何内容(该内容可能会与哈希密码一起被盗...)
盐不会附加到哈希表上!将salt添加(或前置)到明文密码中,然后将salt和密码一起输入到哈希算法以生成哈希。这就是为什么您可以将盐直接与哈希值一起存储的原因。但是,当然,简单的盐化哈希除了对您的心脏有害之外,已经不足以安全地存储凭据。