最佳做法:添加密码?


145

我遇到了一个讨论,在该讨论中,我了解到我实际上在做的并不是给密码加盐,而是给它们添加了胡椒粉,从那时起,我就开始使用以下功能:

hash_function($salt.hash_function($pepper.$password)) [multiple iterations]

忽略选择的哈希算法(我希望这是关于盐和胡椒的讨论,而不是特定算法的讨论,但我使用的是安全算法),这是安全的选择还是我应该做一些不同的事情?对于那些不熟悉这些术语的人:

  • 是通常存储与设计,使其不可能使用哈希表来破解密码的数据库中的字符串中的随机生成值。由于每个密码都有自己的特色,因此必须将所有密码单独强行破解。但是,由于盐与密码哈希一起存储在数据库中,因此数据库泄密意味着同时丢失两者。

  • 胡椒是从中旨在是秘密的数据库(在应用程序的源代码通常硬编码)分开存储站点范围静态值。使用它是为了避免对数据库造成危害,不会导致整个应用程序的密码表都是蛮力的。

我有什么遗漏的东西吗?保护密码安全的最佳选择是保护我的用户的安全吗?这样做是否有潜在的安全缺陷?

注意:出于讨论目的,假设应用程序和数据库存储在单独的计算机上,不共享密码等,因此违反数据库服务器并不自动意味着违反了应用程序服务器。


3
不是重复,但是极其相关:stackoverflow.com/questions/16594613/...
ircmaxell

Answers:


307

好。眼看着,因为我需要写这个,并,我会独自做最后一次典型的答案对辣椒。

辣椒的明显上升

似乎很明显,胡椒应该使哈希函数更安全。我的意思是,如果攻击者仅获取您的数据库,那么您的用户密码应该是安全的,对吗?看起来合乎逻辑,对吧?

这就是为什么很多人认为辣椒是个好主意的原因。这说得通”。

辣椒的现实

在安全和密码学领域,“有意义”是不够的。为了使它被认为是安全的,必须证明某些东西使其有意义。另外,它必须以可维护的方式实现。无法维护的最安全的系统被认为是不安全的(因为该安全性的任何部分发生故障,整个系统都会崩溃)。

辣椒既不适合可验证的模型,也不适合可维护的模型。

辣椒的理论问题

现在我们已经做好了准备,让我们来看一下辣椒出了什么问题。

  • 将一个哈希值馈入另一个哈希值可能很危险。

    在您的示例中,您这样做hash_function($salt . hash_function($pepper . $password))

    从过去的经验中我们知道,仅将一个哈希结果“馈入”另一个哈希函数会降低整体安全性。原因是两个哈希函数都可能成为攻击的目标。

    这就是为什么像PBKDF2这样的算法使用特殊的运算来组合它们(在这种情况下为hmac)的原因。

    关键是,尽管这没什么大不了的,但扔掉它也不是一件小事。加密系统旨在避免出现“应该工作”的情况,而是集中于“旨在工作”的情况。

    尽管这似乎纯粹是理论上的,但实际上并非如此。例如,Bcrypt不能接受任意密码。所以路过bcrypt(hash(pw), salt)的确可以导致远弱哈希比bcrypt(pw, salt)如果hash()返回的二进制字符串。

  • 反对设计

    bcrypt(和其他密码哈希算法)的设计方法是使用盐。从未引入胡椒的概念。这看似微不足道,但事实并非如此。原因是盐不是秘密。这只是攻击者可以知道的值。另一方面,从定义上讲,胡椒粉是加密的秘密。

    当前的密码哈希算法(bcrypt,pbkdf2等)均设计为仅采用一个秘密值(密码)。完全没有研究过向该算法添加其他秘密。

    这并不意味着它不安全。这意味着我们不知道它是否安全。安全性和加密技术的一般建议是,如果我们不知道,那就不是。

    因此,在密码学家设计和审查用于秘密值(辣椒)的算法之前,不应将当前算法与它们一起使用。

  • 复杂性是安全的敌人

    信不信由你,复杂性就是安全的敌人。使算法看起来很复杂可能是安全的,也可能不是。但是,这种方法并不安全的可能性很大。

辣椒的重大问题

  • 这是无法维护的

    您对胡椒的实现无法旋转胡椒键。由于在单向功能的输入处使用了花椒,因此在该值的整个生命周期内都无法更改花椒。这意味着您需要提出一些怪异的技巧来使其支持密钥旋转。

    这是非常重要的,因为每当您存储加密机密时都需要它。没有机制(周期性地和在破坏之后)旋转密钥是一个巨大的安全漏洞。

    您当前的Pepper方法将要求每个用户轮换让其密码完全无效,或者等到他们的下一次登录轮换使用(这可能永远不会)...

    基本上,这使您的方法立竿见影。

  • 它要求您滚动自己的加密货币

    由于当前没有算法支持胡椒的概念,因此您需要编写算法或发明新的算法来支持胡椒。而且,如果您无法立即看到为什么这是一件非常糟糕的事情:

    从最笨拙的业余爱好者到最好的密码学家,任何人都可以创建自己无法破解的算法。

    永远不要投出自己的加密货币...

更好的方法

因此,在上面详述的所有问题中,有两种处理情况的方法。

  • 只需使用现有的算法

    如果您正确地使用bcrypt或scrypt(代价高昂),则除最弱的字典密码以外的所有密码都应在统计上安全。以成本5哈希bcrypt的当前记录是每秒71,000个哈希。以这种速度,即使是6个字符的随机密码也要花费数年才能破解。考虑到我的最低建议成本为10,这将每秒的哈希值减少了32倍。因此,我们只说每秒2200个哈希值。以这种速度,即使是某些词典短语或修饰语也可能是安全的。

    此外,我们应该在门口检查那些较弱的密码类别,并不允许它们进入。随着密码破解工作变得越来越先进,密码质量要求也应随之提高。它仍然是一个统计游戏,但是具有适当的存储技术和强大的密码,每个人实际上都应该非常安全...

  • 存储前对输出哈希进行加密

    安全领域中存在一种算法,该算法旨在处理上文所述的所有问题。这是分组密码。很好,因为它是可逆的,所以我们可以旋转键(是的!可维护性!)。很好,因为它已按设计使用。很好,因为它没有为用户提供任何信息。

    让我们再次看那条线。假设攻击者知道您的算法(这是安全性所必需的,否则就是通过隐蔽性实现的安全性)。使用传统的胡椒方法,攻击者可以创建一个定点密码,并且由于他知道盐和输出,因此可以强行使用胡椒。好的,这是一个远景,但这是可能的。有了密码,攻击者将一无所获。而且由于盐是随机的,因此哨兵密码甚至都不会帮助他/她。因此,剩下的最好的办法就是攻击加密形式。这意味着他们首先必须攻击您的加密哈希以恢复加密密钥,然后再攻击哈希。但是,关于密码攻击的研究很多,因此我们要依靠它。

TL / DR

不要用辣椒。它们有很多问题,还有两种更好的方法:不使用任何服务器端机密(是的,可以)和在存储之前使用分组密码对输出哈希进行加密。


6
感谢您包含加密哈希值的最后一部分,这是我完全同意的答案。如果加密将成为您的密码api的一部分,那么就没有理由不使用它,所以也许……(我很乐意为其编写文档)
martinstoeckli

2
@martinstoeckli:我不同意将加密步骤添加到简化的哈希API中。原因是秘密(密钥)的存储比人们意识到的要难得多,并且用脚射击自己也很容易。对于99.9%的用户而言,除了最简单的密码外,原始bcrypt足以应付所有其他用户……
ircmaxell 2013年

7
@ircmaxell-另一方面,您什么也不会放松。在最坏的情况下,当密钥已知时,攻击者仍必须破解BCrypt哈希(与未加密情况相同)。这与存储用于加密数据的密钥不同,这与添加服务器端机密有关。只要攻击者无法控制服务器/代码,即使是硬编码的密钥也可以保护那些弱密码。这种情况并不少见:除了SQL注入外,还丢弃了备份,丢弃了服务器……可能导致这种情况。许多PHP用户在托管服务器上工作。
martinstoeckli 2013年

2
@martinstoeckli我必须在这里同意ircmaxwell,我认为加密不属于密码api。尽管可以注意到,为了获得最大的安全性,对哈希进行加密是可以使用的另一项规定。
foochow

我对存储之前的输出加密有疑问。如果我没记错的话,通常使用加密密钥对消息进行唯一或瞬时加密。但是,如果您有200,000个用同一密钥加密并存储在一起的用户密码,这是否使攻击密钥更容易?现在,每年有二十万的消息,这一比例仅为1或2
AgmLauncher

24

首先,我们应该谈一谈胡椒粉确切优点

  • Pepper可以保护弱密码免受字典攻击,在特殊情况下,攻击者可以读取数据库(包含哈希),但不能访问Pepper的源代码。

典型的情况是SQL注入,丢弃备份,丢弃服务器...这些情况并不像听起来那样罕见,并且通常不受您的控制(服务器托管)。如果您使用...

  • 每个密码唯一的盐
  • 像BCrypt这样的慢速哈希算法

...强大的密码得到了很好的保护。在这种情况下,即使知道了盐,也几乎不可能强行使用强密码。问题是弱密码,它们是蛮力字典的一部分,或者是它们的派生产品。字典攻击将很快显示出这些信息,因为您仅测试最常用的密码。

第二个问题是如何使用胡椒粉

通常推荐的应用胡椒的方法是在将密码和胡椒传递给哈希函数之前,将密码和胡椒结合起来:

$pepperedPassword = hash_hmac('sha512', $password, $pepper);
$passwordHash = bcrypt($pepperedPassword);

不过,还有另一种更好的方法:

$passwordHash = bcrypt($password);
$encryptedHash = encrypt($passwordHash, $serverSideKey);

这不仅允许添加服务器端机密,还允许交换$ serverSideKey(如果需要)。该方法需要更多的工作,但是如果代码一旦存在(库),则没有理由不使用它。


简而言之,您会说胡椒粉确实可以增加盐的安全性吗?感谢您提供有关实施的帮助。
Glitch Desire

1
@LightningDust-是的,对于弱密码,只要胡椒保持秘密,它就会这样做。它可以缓解某些定义明确的威胁类型。
martinstoeckli 2013年

@martinstoeckli绝对是实现此目标的好方法。很高兴看到有一定安全经验的人支持此方法。MySQL AES_ENCRYPT($passwordHash, $serverSideKey)调用也将是实现此目标的合适方法吗?
foochow

1
@Foo_Chow-我不知道MySQL函数的实现,但似乎他们使用EBC模式来避免IV矢量。与已知的纯文本一起使用(哈希值始终以相同的字符开头),这可能是一个问题。在我的主页上,我发布了一个示例实现,用于处理这种加密。
martinstoeckli 2013年

@martinstoeckli有趣,对概念不太熟悉;但是,对于最可靠的结果,似乎需要IV。似乎并没有增加太多的额外费用。
foochow

2

盐和胡椒粉的要点是增加称为彩虹表的预先计算的密码查找的成本。

通常,很难为单个哈希找到冲突(假设哈希是安全的)。但是,如果哈希值很短,则可以使用计算机将所有可能的哈希值生成到硬盘上的查找中。这称为彩虹表。如果创建彩虹表,则可以进入世界,并快速找到任何(未加盐且未加盐的)哈希的合理密码。

胡椒的重点是使破解您的密码列表所需的彩虹表独特。因此,浪费了更多的时间在攻击者身上以构建彩虹表。

然而,重点在于使每个用户的彩虹表对于用户而言是唯一的,从而进一步增加了攻击的复杂性。

实际上,计算机安全的要点几乎是从来没有(在数学上)使其不可能,而在数学上和物理上都不可行(例如,在安全系统中,它将利用Universe中的所有熵(甚至更多)来计算单个用户的密码)。


那么,盐+胡椒粉是否能提供比盐更多的安全性?还是我会放弃辣椒并运行更多的scrypt迭代?
Glitch Desire

2
彩虹表的主要特点是,您无需为特定攻击创建一个彩虹表,而是下载一个预先存在的彩虹表。距离Google仅几步之遥,可以找到流行彩虹算法的冗长彩虹表!
理查德

1
@LightningDust我自己想不出任何原因。但是,Richard在另一个话题中提出了一个。您可以将花椒隐藏在源代码中,这意味着攻击者需要另一个位置来访问彩虹表。
阿隆(Aron)2013年

@Aron-那就是我的想法,因为我们有与数据库服务器分离的应用程序服务器(也就是说,如果您进入root数据库服务器,您仍然无法访问我们的应用程序服务器),这将胡椒粉隐藏在源代码中(在我们的配置文件)将提供额外的安全性。
Glitch Desire

1

无法看到在源代码中存储硬编码值具有任何安全性。默默无闻是安全性。

如果黑客获取了您的数据库,他将能够开始强行强制使用您的用户密码。如果该黑客设法破解了一些密码,那么很快就可以识别您的胡椒。


1
对于未加盐的密码表,这将使预计算的Rainbow表无效。简而言之,即使攻击者知道您的辣椒,他也需要创建一个新的彩虹表。
阿隆(Aron)2013年

3
它基于数据库中不可用的数据来增强哈希,这是一件好事。数据库中的内容可能会通过漏洞被揭示-用相同的方式访问代码中的值的可能性较小。
理查德

盐是一种功能,即使成功强行使用密码也只会为您提供该密码,而无助于您获得Pepper本身的价值。
Glitch Desire

1
@LightningDust我认为您的意思是“哈希是活板门函数”。是的,不可能从安全哈希中找出您的盐和/或胡椒粉(实际上,这是安全哈希的定义)。
阿隆(Aron)2013年

6
@Aron通过默默无闻的安全性可以是用作防御层的有效技术。关键是永远不要依赖它作为防御,而应该用来“减慢攻击者的速度”。如果不是这种情况,就不会使用像蜜罐这样的东西。相反,只要我们不依赖应用程序的安全性,我们就可以通过模糊性有效地利用安全性,以帮助降低攻击者的速度。
ircmaxell,2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.