请注意:我知道用于安全密码存储哈希的正确方法是scrypt或bcrypt。这个问题不是在实际软件中实现的,而是我自己的理解。 >如何安全地对密码进行哈希加密?
HMAC-为什么不使用HMAC进行密码存储?密码验证程序要存储在以下位置:

$verifier = $salt + hash( $salt + $password )


其中:



hash()是一种加密哈希算法

$salt是随机的,均匀分布的高熵值

$password是用户输入的密码

有人建议在其中添加密钥混合(有时称为胡椒粉)。胡椒是秘密的,高熵的,特定于系统的常数。

理由似乎是,即使攻击者掌握了密码验证程序,也很有可能他或她没有知道胡椒的价值。因此,发起一次成功的攻击变得更加困难。

还是基于错误的假设而提高了安全性?它)的附加$salt密钥并不能改善盐的作用。

评论

您可以为哈希加盐,以避免它们被彩虹表破解。然后,三元组并不需要太多为混合添加一个常量。

与security.stackexchange.com/questions/211/password-hashing相关但不完全相同

如果我理解正确,并且在我所链接的《问答》中对此进行了讨论,则Pepper可以“ ...通过将一部分难题存储在其他位置来帮助缓解某些折衷方案(例如,数据库备份丢失)”(@ RoryMccune) 。也可以将您的哈希值与其他哈希值区分开-如果构造了足够大的彩虹表...

这个问题专门问胡椒。有关更广泛的信息,请参见IT安全性StackExchange上其他地方更完整的讨论,其中涉及密码散列的更一般主题

@commonSenseCode,是的,可以反对使用胡椒粉进行大量争论。但是,有很多争论并不能自动提出更好的观点。以胡椒为例,当在正确的环境中使用时,到目前为止,它已被广泛接受为一种提高安全性的方法。自2017年以来,甚至NIST也开始推荐它。

#1 楼

在某些情况下,花椒会有所帮助。
作为一个典型的例子,假设您正在构建一个Web应用程序。它由webapp代码(在某些webapp框架中运行,ASP.NET MVC,在Python上的金字塔无关紧要)和用于存储的SQL数据库组成。 Webapp和SQL DB在不同的物理服务器上运行。
对数据库的最常见攻击是成功的SQL Injection Attack。这种攻击不一定能访问您的Web应用程序代码,因为Web应用程序在不同的服务器和用户ID上运行。
您需要将密码安全地存储在数据库中,并以:
$hashed_password = hash( $salt . $password )

其中$salt$hashed_password表示形式一起以明文形式存储在数据库中,并为每个新的或更改的密码随机选择。 hash是一种缓慢的加密安全哈希函数,请参阅https://security.stackexchange.com/a/31846/10727了解更多背景知识。
问题是,添加常数几乎为零。值,并且在SQL注入攻击期间通常不会破坏应用程序代码,那么下面的代码是否比上面的代码好得多?
$hashed_password = hash( $pepper . $salt . $password )

其中$salt以明文形式存储在数据库中,而$pepper是一个co nstant以明文形式存储在应用程序代码中(如果在多个服务器上使用该代码或源是公共的,则进行配置)。
添加此$pepper很容易-您只需在代码中创建一个常量,然后在其中输入一个较大的加密安全随机值(例如来自/ dev / urandom hex或base64编码的32byte),然后在密码哈希中使用该常量功能。如果您已有用户,则需要迁移策略,例如,在下次登录时重新哈希密码,并在哈希旁边存储密码哈希策略的版本号。
答案:
使用$pepper确实会增加如果数据库受到破坏并不意味着应用程序受到破坏,则密码散列的强度。在不了解Pepper的情况下,密码仍然完全安全。由于存在特定于密码的盐,您甚至无法找出数据库中的两个密码是否相同。
原因是hash($pepper . $salt . $password)有效地构建了以$pepper作为键,$salt.$password作为输入的伪随机函数(对于健全的hash候选对象,例如具有SHA *,bcrypt或scrypt的PBKDF2)。伪随机函数的两个保证是,您不能从秘密密钥下的输出推论输入,也不能在不知道密钥的情况下从输入推论输出。这听起来很像哈希函数的单向属性,但是不同之处在于,使用像密码这样的低熵值,您可以有效地枚举所有可能的值,并在公共哈希函数下计算图像,从而找到其值图像与原图像匹配。使用伪随机函数,没有键就无法做到这一点(即没有辣椒),因为没有键就无法计算单个值的图像。
如果您可以长时间访问数据库并且仍然可以从外部正常使用该应用程序,则$salt在此设置中的重要作用将发挥作用。如果没有$salt,则可以将您控制的帐户的密码设置为已知值$passwordKnown,然后将哈希值与未知密码$passwordSecret的密码进行比较。与hash($pepper . $passwordKnown)==hash($pepper . $passwordSecret)一样,当且仅当$passwordKnown==$passwordSecret可以将未知密码与任何选定值进行比较(出于技术上的考虑,我假设哈希函数具有抗冲突性)。但是,只有当分别为hash($pepper . $salt1 . $passwordKnown)==hash($pepper . $salt2 . $passwordSecret)$salt1 . $passwordKnown == $salt2 . $passwordSecret随机选择$salt1$salt2$passwordKnown时,使用盐才能得到$passwordSecret,盐将永远不会相同(假设随机数足够大,例如256bit),因此您将无法再将密码与彼此。

评论


嗯,编辑消除了@Jesper Mortensen撰写的答案中存在的大部分不确定性。也许应将编辑回滚并移至单独的答案?

–雅科
2011年4月23日在22:08

这里的论点很不错,我倾向于同意。但是,如果可以避免,请不要在代码中放置常量,而应将其设置为某种配置变量(不存储在数据库中,也不存储在代码中)。

– frankodwyer
2011年4月24日上午9:30

@Jacco:我同意这个答案的语气随着所做的编辑而改变。但是,接下来,看看谁进行了编辑,我现在很自在(在其范围内)这个答案是正确的,因此我很乐意将其保留为现在。 :-)

– Jesper M
2011年4月24日在11:27

我同意这样的说法:添加常数值几乎是零的努力。的确如此,尽管它不如添加密码重要,但我认为没有理由排除某种形式的胡椒来提供应用程序代码级别的保护。

–渴猿
2014年2月11日在18:20

@frankodwyer,您甚至可以同时拥有两者。 Web服务器上代码中的常量以及另一台服务器上“ config”实体中的另一个常量。

–起搏器
2014年12月2日在7:40

#2 楼

(注意:使用盐仅是工作的一半;您还需要使散列函数变慢-因此攻击单个低熵密码仍然很困难。缓慢性通常是通过多次迭代或对盐和密码的10000个副本。)

您的“胡椒粉”所做的是将哈希转换为MAC。用散列函数创建一个好的,安全的MAC并不容易,因此,您最好使用HMAC而不是自制的构造(理论上的说法是,抗冲突的散列函数不一定与随机预言是无法区分的)。

使用MAC,您可以从以下角度获得一些安全性:攻击者对数据库的读取访问可能不再是一个真正的问题。 MAC密钥(“ pepper”)可以集中保密性需求。但是,这依赖于MAC也是一种单向函数,这是您可以从许多MAC构造(包括HMAC)中获得的属性,但是从密码上来说,并不能真正保证它的存在(有些微妙之处)。 br />“胡椒粉”意味着您需要管理一个密钥,包括以一种不会重启的方式进行的安全存储。密钥很小并且适合RAM,但是由于存储要求,还不清楚它是否真正提高了安全性。可以读取整个数据库的攻击者通常还可以读取整个硬盘,包括任何“受保护的”文件。较小的按键可能允许某些高级设置,例如密钥存储在智能卡上,该智能卡在引导时使用,但之后未保持连接状态。综上所述,加薪是否值得付出的努力完全取决于具体情况,总的来说,为了避免增加复杂性,我建议不要这样做。

评论


@Jacco:如果哈希函数有任何好处,那么不能,您不会通过添加已知的前缀或后缀来以任何方式削弱它。但是,具有良好的哈希功能并不完全等同于具有良好的MAC(区别很小,但却是真实的),因此需要遵循经过充分研究的构造,例如HMAC。对于一本好书,您可以尝试应用密码学手册(cacr.math.uwaterloo.ca/hac)(与Schneier的“应用密码学”不同)。

–托马斯·波宁(Thomas Pornin)
2011年4月22日在20:54

@杰斯珀:我们在谈论同一件事,但观点截然不同。 “ pepper”仅在攻击者不知道的情况下才能提高安全性-是否真的是不容易猜测的,尤其是在Webapp和数据库位于不同机器上的设置中。 Pepper不会单独降低安全性,除了会增加安装复杂性(攻击者必须不知道的值是密钥,而密钥管理是不直接的)。同样,使用秘密胡椒,安全性的提高取决于该构造是否为良好的MAC。

–托马斯·波宁(Thomas Pornin)
11年4月23日在14:09

-1表示“可以读取整个数据库的攻击者通常也可以读取整个硬盘”。显然,您不是渗透测试人员,请不要做这样的假设。

–rook
2012年7月19日在9:23

@Lex,不必要的复杂性是安全的大敌。安全性本身就很复杂。

–起搏器
2014年11月2日在21:29



@rook,指出答案中的缺陷比攻击作者的凭据要好,因为指出缺陷会增加其他用户可以用来判断答案的信息。我会在这里做。数据库凭证通常等于整个操作系统访问权限,这是不正确的。数据库服务器经常与运行它们的应用程序分开,后者通过网络连接。或者,即使数据库用户无法脱离其沙箱,数据库软件中的缺陷也可能导致对数据库的完全访问。

– Madumlao
16 Mar 19 '16 at 10:17

#3 楼

我想指出一下胡椒真正可以做什么。

什么时候胡椒有帮助?只要攻击者可以访问数据库中的哈希值,但无法控制服务器,因此就不知道这个问题。这对于SQL注入来说是典型的,因为它很容易做到,可能是更常用的攻击之一。

Pepper有什么改进?

/>
即使正确使用了慢速键派生功能,也可以通过字典攻击轻松获得此密码。将最常用的密码放入字典中,并使用此弱密码进行暴力破解。

$hashValue = bcrypt('12345', $cost, $salt);


在胡椒中,弱密码的长度增加,现在包含特殊字符,并且更重要的是,您不会在字典中找到它。因此,只要Pepper保持秘密,它就可以防止字典攻击,在这种情况下,它可以保护弱密码。

编辑:

有一种更好的添加方法服务器端密钥,而不是用作胡椒粉。使用胡椒,攻击者必须在服务器上获得其他特权才能获取密钥。通过首先计算哈希,然后使用服务器端密钥对哈希进行加密(双向加密),我们可以获得相同的优势。这使我们可以选择在必要时交换密钥。

$hashValue = bcrypt('12345anm8e3M-83*2cQ1mlZaU', $cost, $salt);


评论


我建议bcrypt(hash_mac('sha256',$ password,$ pepper),$ salt)

–雅科
2012年11月2日16:06

@Jacco-刚刚添加了一个使用hmac的示例。

–martinstoeckli
2012年11月2日,21:42

我不确定您的示例使用哪种语言,但是如果它与语言无关,则将更加清楚

–雅科
2012年11月5日在7:23

@Jacco-它是PHP,但是函数bcrypt是虚构的,因为PHP本身还没有提供这样的函数(在5.5之前),但是函数hash_hmac存在。我试图编辑答案,所以所有令人困惑的部分都被删除了,您认为我还能做些什么呢?

–martinstoeckli
2012年11月5日8:00

#4 楼

关于Unix密码的盐化和迭代发明的论文(Password Security:A Case History,Morris&Thompson,1978年)也描述了胡椒的等效性:


用户密码的八个字符用作DES的密钥。然后使用该算法对常量进行加密。尽管此常量在
时刻为零,但它易于访问并且可以依赖于安装。


我还没有听说过使用它。还有其他人吗?

评论


我认为所有现代发行版都使用基于散列函数(而不是像DES这样的加密函数)的东西,因此该功能不再可用。

–布伦丹·朗(Brendan Long)
2012年11月15日18:16

#5 楼

只是一个顺便说一句,新的NIST数字身份准则(草案)强烈建议也使用Pepper:

https://pages.nist.gov/800-63-3/sp800-63b.html #sec5

5.1.1.2记忆的秘密验证程序:


...一个带键的哈希函数(例如HMAC [FIPS198-1])与散列的身份验证器分开存储(例如,在硬件安全模块中)的存储应该用于进一步抵抗针对存储的散列的身份验证器的字典攻击。

评论


哇,我多年来一直提倡使用胡椒,但是人们很少无缘无故地实施胡椒。我不知道NIST现在也推荐它!感谢您的答复,这应该更高。

–吕克
18-10-11在8:43

#6 楼

请考虑以下情形:

我将使用SQL注入闯入网站X,以检索用户列表以及其密码哈希和盐。假设网站X也在使用全局Pepper。

我要做的就是在SQL注入之前使用我知道的用户名和密码在网站X上注册一个用户。然后,对于数据库中的特定记录,我会知道密码哈希,纯文本密码,salt(以纯文本存储),而根据这一记录,对我来说,破解全局胡椒将在计算上变得微不足道。

所以,实际上,胡椒粉可以使攻击者在微不足道的开销时间内减速。他们不必像预期那样强行使用密码+盐+胡椒粉。

以上是选择的明文攻击形式。只要攻击者知道算法(hash()),输出($ hashed_pa​​ssword)以及除输入之外的所有输入(“ constants” $ salt&$ password和“ variable” $ pepper),他们就可以“求解x就像线性代数方程式(h = s + p + x == hsp = x),但当然是蛮力。使Pepper的长度超过bcrypt的限制56字节(448位),增加了时间成本,与bcrypt一样好,但仍不如scrypt好。因此,只要胡椒足够长,它就是一种进步。

评论


如果Pepper是128位随机值怎么办?根据salt和明文密码值破解它仍然微不足道吗?盐和胡椒粉值之所以有用的原因是,您可以轻松地使其足够长(128位),而不必记住它,这就是为什么通过蛮力破解它从来都不是一件容易的事。

–void_in
13年8月31日在10:25

如果Pepper是128位随机值,那么破解当然还是很容易的。但是,您必须记住以下几点:-您要在每次验证时将此值添加到哈希函数的开销中-胡椒是全局性的,只需用蛮力破解一次,而不是为每个记录破解一次-您会更好比胡椒增加了盐的长度

– Alex R
2015年3月10日在22:09



任何甚至部分合适的哈希函数(例如bcrypt,脚本或什至是某些sha的多次迭代)的成本都不取决于密钥的长度,因此这是错误的。如果正确选择了哈希函数,而不仅仅是使用sha256的单次迭代,那么花椒只需要将初始密码提高到50位熵即可使其成为防弹符号,即使不是几个世纪。当然,就像@void_in所说的那样,我们将其提升到128位或256位,只是因为可以。

–彼得
2015年12月10日20:00

#7 楼

对服务器如何隐藏全局Pepper常量不是很熟悉,但我的看法是,渗透到服务器中的黑客迟早会弄清楚如何获取Pepper的价值。
要获得Pepper的价值完全安全将需要特殊的硬件。一种方法是使用服务器中安装的FPGA板。 FPGA将包含用于执行哈希的代码,包括Pepper值,并且所有哈希计算都在FPGA内部进行。使用FPGA,编程可以是一种单向功能。可以对胡椒进行编程,但没有指令可以发送以将其读出。胡椒粉将存储在锁在保险箱中的纸上。
如果Pepper是随机生成的128个以上的位,则没有确定它的实用方法。

评论


有可用的加密模块执行类似的操作-用于存储+验证密码和/或密钥的单向设备。

– Mark K Cowan
16年7月31日在17:07