$pwd
本身包含$pwd
的某些情况。我想知道盐是否应该单独存储,或者如果攻击者同时获取哈希值和盐是否可以。为什么?
#1 楼
TL; DR-您可以以纯文本格式存储盐,而无需进行任何形式的混淆或加密,但不要仅仅将其分发给想要的人。我们使用盐的原因是为了停止计算前攻击,例如彩虹表。这些攻击涉及创建哈希及其明文的数据库,以便可以搜索哈希并立即将其转换为明文。
例如*:
大多数表还包括一个常用密码列表:
因此,如果我的密码哈希为
9272d183efd235a6803f595e19616c348c275055
,那么在数据库中搜索它并发现明文为bacon4
将非常容易。因此,您无需花几个小时来破解哈希(好的,在这种情况下,在像样的GPU上要花几分钟,但是稍后再讨论),您可以立即获得结果。显然,这不利于安全!所以,我们用盐。盐是随每个密码存储的随机唯一令牌。假设salt为
5aP3v*4!1bN<x4i&3
,哈希为9537340ced96de413e8534b542f38089c65edff3
。现在,您的密码数据库已无用,因为没有人拥有包含该哈希的彩虹表。为每种可能的盐生成彩虹表在计算上是不可行的。所以现在我们迫使坏蛋再次开始破解哈希。在这种情况下,由于我使用了错误的密码,因此很容易破解,但是比他能够在十分之一秒的时间内查到密码要好得多!
盐的目的只是为了防止创建预先生成的数据库,它不需要在数据库中进行加密或隐藏。您可以将其以纯文本格式存储。目的是迫使攻击者一旦获得数据库就必须破解哈希,而不是只能在彩虹表中查找所有哈希。
但是,有一个警告。如果攻击者可以在侵入您的数据库之前悄悄地获取盐分,例如通过一些向任何需要盐的人提供盐的脚本,他可以像没有盐一样轻松地为该盐生成彩虹表。这意味着他可以默默地使用您的管理员帐户的费用,生成一个漂亮的大彩虹表,然后入侵您的数据库并立即以管理员身份登录。这样您就没有时间发现发生了违规行为,也没有时间采取行动来防止损坏,例如更改管理员密码/锁定特权帐户。这并不意味着您应该隐藏盐或尝试对其进行加密,而只是意味着您应该设计系统,以使盐的唯一途径就是闯入数据库。
要考虑的另一个想法是胡椒。胡椒是第二种盐,在各个密码之间保持不变,但未存储在数据库中。我们可以将其实现为
H(salt + password + pepper)
或用于密钥派生功能的KDF(password + pepper, salt)
-我们将在后面讨论。这样的值可以存储在代码中。这意味着,攻击者必须同时访问数据库和源代码(如果是ASP .NET,CGI等,则必须访问Web应用程序二进制文件)才能尝试破解哈希。此想法仅应用于补充其他安全措施。当您担心SQL注入攻击(攻击者只能访问数据库)时,Pepper是有用的,但是攻击者只能访问数据库,但是随着人们转向参数化查询,这种模型(慢慢地)变得越来越少见。您正在使用参数化查询,对不对?有些人认为胡椒粉通过遮盖力构成安全性,因为您只是使胡椒粉变得晦涩难懂,但这在一定程度上是正确的,但这并不是说这种想法没有根据。现在,我们处于一种情况,攻击者可以强行使用每个单独的密码哈希,但不再可以在Rainbow表中搜索所有哈希并立即恢复纯文本密码。那么,我们现在如何防止暴力攻击?
现代图形卡包含具有数百个内核的GPU。每个核心都非常擅长数学,但并不擅长决策。它每秒可以执行数十亿次计算,但是在执行需要复杂分支的操作时非常糟糕。加密哈希算法适合于第一类计算。因此,可以利用诸如OpenCL和CUDA之类的框架来大规模加速哈希算法的操作。使用性能不错的图形卡运行oclHashcat,您每秒可以计算出10,000,000,000个MD5哈希值。 SHA-1也不慢。那里有专用的GPU破解设备,其中包含6个或更多的高端图形卡,从而使MD5的破解速度超过每秒500亿哈希。让我来说明一下:这样的系统可以在不到4分钟的时间内强行使用8个字符的字母数字密码。
像MD5和SHA-1这样的哈希值对于这种情况来说太快了。一种解决方法是执行加密哈希算法的数千次迭代:
86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 a
e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98 b
84a516841ba77a5b4648de2cd0dfcb30ea46dbb4 c
...
948291f2d6da8e32b007d5270a0a5d094a455a02 ZZZZZX
151bfc7ba4995bfa22c723ebe7921b6ddc6961bc ZZZZZY
18f30f1ba4c62e2b460e693306b39a0de27d747c ZZZZZZ
这会减慢哈希计算的速度,但并不完美。一些倡导者使用SHA-2系列哈希,但这并不能提供太多额外的安全性。一种更可靠的方法是将密钥推导函数与工作因子一起使用。这些功能需要输入密码,密码和工作因素。工作因数是一种根据您的硬件和安全性要求扩展算法速度的方法:
5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8 password
e38ad214943daad1d64c102faec29de4afe9da3d password1
b7a875fc1ea228b9061041b7cec4bd3c52ab3ce3 letmein
5cec175b165e3d5e62c9e13ce848ef6feac81bff qwerty123
两种最受欢迎的KDF是PBKDF2和bcrypt。 PBKDF2通过执行密钥HMAC的迭代来工作(尽管它可以使用分组密码),而bcrypt则通过计算和组合来自Blowfish分组密码的大量密文块来工作。两者的工作大致相同。较新的bcrypt变种scrypt的工作原理相同,但是由于内存带宽的限制,引入了难于记忆的操作,因此在GPU和FPGA场上进行破解是完全不可行的。更新:截至2017年1月,最新的哈希算法是Argon2,该算法在密码哈希竞赛中获胜。
希望这对您有所了解存储密码时我们会遇到的问题,并回答您有关盐存储的问题。我强烈建议您查看Jacco答案底部的“感兴趣的链接”以供进一步阅读,以及以下链接:
基于表单的网站身份验证权威指南
开放式Web应用程序安全项目(OWASP)
StackOverflow上的类似答案
评论
+1,阿们我希望我们在哪里能够创建一个索引/目录,以指向对此类常见/普遍问题的良好答案。更重要的是,因为常见/常见问题也经常吸引相当不安全的答案。
–雅科
2012年7月21日在9:04
前几天,我在阅读有关Scrypt的文章,它是一种KDF,旨在比Bcrypt和PBKDF2更加昂贵。这可能是值得考虑的另一种选择。
–加里特·奥尔布赖特(Garrett Albright)
2012年7月21日在23:24
@Polynomial可能还会添加一个链接到stackoverflow.com/questions/1645161/…?
–雅科
2012年10月26日在12:14
只是为了强调:请确保为每个密码使用不同的符号!如果为每个密码使用相同的盐,则蛮力算法的计算复杂度将大大降低。此外,攻击者仅通过比较散列就可以查看哪些用户使用相同的密码,这可能会对跨多个帐户重复使用密码的用户产生匿名性。
–user1354557
16年6月15日在15:06
真的很好的答案。但是您仍然没有回答“我在哪里存储随机盐”的问题?您需要使用随机盐检查输入的密码是否正确...我错了吗?
–科洛布峡谷
18年1月9日在21:18
#2 楼
盐并不意味着是秘密的,相反,盐通过确保哈希结果对于每个使用的实例都是唯一的而“起作用”。这是通过为每个计算出的哈希值选择不同的随机盐值来实现的。已知盐的意图不会受到损害;攻击者仍然需要分别攻击每个哈希。因此,您可以将盐与哈希密码一起存储。
相关链接:如何安全地哈希密码?密码哈希添加盐+胡椒粉还是足够盐?盐生成和开源软件
评论
请记住,如果盐泄漏(例如,通过代码中的缺陷),攻击者可以提前为该盐建立彩虹表。如果有人以后偷了您的哈希,这会使您很难采取预防措施,因为他们可以立即破解密码(他们已经有了Rainbow表!)并访问该帐户。
–多项式
2012年7月20日在7:51
@Polynomial您的观点很不错。也许您想写一个涵盖您所说内容的答案?我当然会赞成它,并且以这种方式阅读要容易得多。
–user10211
2012年7月20日13:17
@Terry Chia:假装比较常见。
– Piskvor离开了建筑物
2012年7月20日13:41
除了哈希,加盐的密码。
–扎克
17-6-28在19:09
@Polynomial然后将盐存储在哪里?看来,如果攻击者发现了盐就可以闯入数据库?
–科洛布峡谷
18年9月9日在21:19
#3 楼
可以并且应该将盐存储在加盐和散列的密码旁边。此外,salt应该对每个密码都是唯一的。其目的是使通过使用预先计算的密码哈希对表攻击泄漏的密码数据库变得不可行。
之所以可行,是因为只有在攻击者获得实际的(强化的)密码后,盐才会被攻击者知道;从而使任何预先计算的攻击都变得不可能。 (如果您不是每个密码使用唯一的盐,而是全局密码,则可能仍会使用预先计算的表-尽管必须针对应用程序的盐专门对其进行预先计算。)
存储时除了密码旁边的盐以外,您可能会获得一些额外的安全性,但这样做几乎无法达到目的:每次要验证密码时,都需要盐和哈希密码,因此它们必须非常有效。无论如何都是“关闭”(从丰富意义上来说)。
#4 楼
单独存储盐会提供一些额外的安全性,但并不能提供太多的安全性-毕竟,数据库应该是应用程序受保护最好的位置,因此,如果攻击者可以访问数据库,则很可能他可以访问任何其他数据。另一方面,您需要为每个用户分配不同的盐,这意味着您需要大量的盐-将其存储在数据库外部是不可行的。有一种使用所有用户都相同的第二片盐(有时称为花椒),并将其存储在数据库外部(可能存储在环境变量或某种配置文件中),因此攻击者无法通过简单的方式访问它SQL注入。这增加了一些安全性,但是如上所述,不要期望过高,请使用bcrypt或其他慢速哈希方法来防御盐被盗。
#5 楼
我想把您的注意力转向标题为“安全存储密码”的有趣文章。本文的作者介绍了盐和胡椒。而且,他/她认为实际上您不想使用加密哈希函数来存储密码。哈希的两个主要特征是应该是单向的。
计算起来应该便宜。
显然,这些要求是相互矛盾的。因此做出了折衷。您不希望攻击者能够廉价地计算其暴力破解尝试。因此,为了获得更好的安全性,您实际上需要一个密钥派生函数,它是单向的,并且计算时间较长(例如0.1 s)。
有一些方案/实现方式,即所谓的“自适应密钥派生函数”,已经过充分研究并且被认为是安全的(作者姓名三:PBKDF2,bcrypt,scrypt)
评论
此时,您的答案还没有真正买到什么东西,因此您可能应该只在评论中链接文章。不过,这是一篇不错的文章-非常详尽,涵盖了所有基础。我会保留一个书签以供将来参考!
–多项式
2012年7月20日在16:01
好文章!据我所知,PBKDF2是一个自适应密钥派生函数,而BCrypt和SCrypt不是。它们是自适应成本哈希算法。 (差异是细微的,但却是真实的)。
–雅科
2012年7月21日在8:56
多项式:您是对的。我是如此渴望发布这篇文章(我将其保存在书签中,并为它的时机终于到来而感到兴奋),以至于我只是略过了您的答案而完全错过了最后一段。抱歉
–user7610
2012年9月12日下午13:28
#6 楼
我已经从许多公司看到PBKDF2。它们通常形成为$ variant $ cost factor $ 22字符salt $ 31字符哈希,如@Kat所评论。因此,它们只能存储在一个地方。盐和密码可以一起存储,因为每种随机盐都不同,这使得攻击者可以蛮力地使用每个密码。因此,还需要为每种盐重新创建彩虹表。同样,每次都需要强制使用相同的密码。
哈希密码只是安全性的一小部分。每个服务都应要求用户每年或每月更改一次密码。或每个服务都应使用OAuth 2.0。最佳实践是使用已经提供最佳安全性的服务。
#7 楼
好吧,您要在两个不同的框中分别将盐和哈希值分开-希望您理解正确的答案。并确保两者的数量相同,例如256位盐,256位哈希,如果使用简单的隔离盐服务器,则可以提高安全性。评论
为什么在不同的地方存储哈希和盐?
–安德烈·波塔洛夫(Andrei Botalov)
2012年7月20日在20:52
参见例如security.stackexchange.com/a/17449/5501
–安德烈·波塔洛夫(Andrei Botalov)
2012年7月20日在20:54
-1“ 256位哈希”在这里不会给您带来任何好处。该算法不必太慢。分别将哈希和盐类杂散符分开,创建一个全新的问题范围,而是坚持采用最佳实践。
–雅科
2012年7月21日在8:51
评论
@Earlz这不是盐的目的,无论如何都几乎不可能隐藏盐!@Earlz第二种盐叫做花椒,它保护您免受仅可访问数据库的攻击者的侵害。它很有用,但是由于您正在使用参数化查询(正在使用它们,对吗?),SQL注入不是问题,因此攻击者模型的可能性大大降低。
原谅我的无知,但是添加盐之前真的需要对密码进行哈希处理吗?如果您有一个很好的哈希算法,就不应该有所作为,对吧?
@ X-Zero完全没有区别,使用自适应KDF时,它会使事情更加尴尬。
@matejkramny这完全等同于仅使用用户名作为盐,并且出于相同的原因也是很糟糕的:如果攻击者知道他们想要破解的用户名,则他们可以预先计算该用户名的哈希值。在密码中包含密码不会改变任何事情。要阻止它们预先计算哈希,应将盐存储在数据库中,这样它们就无法在自己获取哈希之前获取它,这意味着在危害数据库后,他们需要大量时间来破坏哈希,这为您提供了便利有机会在访问密码之前更改密码。