最佳实践:Salting&辣椒密码?

时间:2013-06-03 07:15:48

标签: security hash passwords salt password-hash

我遇到了一个讨论,其中我了解到我一直在做的事情实际上并没有腌制密码而是给它们加油,而且我已经开始用这样的函数来做这两件事:

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

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

  • salt 是一个随机生成的值,通常与数据库中的字符串一起存储,旨在使得无法使用哈希表破解密码。由于每个密码都有自己的盐,因此必须对它们进行单独的强制攻击才能破解它们;但是,由于salt使用密码哈希存储在数据库中,因此数据库泄露意味着丢失两者。

  • pepper 是与数据库分开存储的站点范围的静态值(通常在应用程序的源代码中硬编码),该值是秘密的。它的使用是为了破坏数据库不会导致整个应用程序的密码表变得暴力破解。

有什么我想念的东西,正在腌制和腌制辣椒密码是保护用户安全的最佳选择吗?这样做有没有潜在的安全漏洞?

注意:为了讨论的目的,假设应用程序&数据库存储在不同的机器上,不共享密码等,因此违反数据库服务器并不会自动意味着破坏应用程序服务器。

5 个答案:

答案 0 :(得分:286)

确定。看到我需要写下这个overover,我将仅就胡椒做一个最后的规范回答。

辣椒的明显上升

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

这就是为什么这么多人认为辣椒是个好主意的原因。它"有意义"。

辣椒的现实

在安全和加密领域,"有意义"还不够。必须要证明才能使其被认为是安全的。此外,它必须以可维护的方式实现。无法保证最安全的系统被认为是不安全的(因为如果该安全的任何部分发生故障,整个系统就会崩溃)。

辣椒既不适合可证明的模型也不适合可维护的模型...

辣椒的理论问题

现在我们已经上台了,让我们来看看辣椒有什么不对。

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

    在您的示例中,您执行hash_function($salt . hash_function($pepper . $password))

    我们从过去的经验中知道"只是喂养"一个哈希结果到另一个哈希函数可以降低整体安全性。原因是两个哈希函数都可以成为攻击目标。

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

    关键在于,虽然这并不是什么大不了的事情,但扔掉它也不是一件小事。加密系统旨在避免"应该工作"案例,而是专注于"旨在工作"例。

    虽然这看似纯粹是理论上的,但实际上并非如此。例如,Bcrypt cannot accept arbitrary passwords。因此,如果bcrypt(hash(pw), salt)返回二进制字符串,则传递bcrypt(pw, salt)确实会导致散列远远弱于hash()

  • 反对设计

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

    当前的密码哈希算法(bcrypt,pbkdf2等)都设计为只接受一个秘密值(密码)。在算法中添加另一个秘密还没有被研究过。

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

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

  • 复杂性是安全的敌人

    信不信由你,Complexity Is The Enemy Of Security。制作看起来复杂的算法可能是安全的,也可能不是。但是,它的安全性非常大。

Peppers的重大问题

  • 不可维护

    您对辣椒的实施排除了旋转辣椒键的能力。由于胡椒用于单向函数的输入,因此您永远不能在值的生命周期内更改胡椒。这意味着您需要提出一些难以理解的黑客攻击来支持密钥轮换。

    非常非常重要,因为每当您存储加密机密时都需要它。没有机制来轮换密钥(定期和违规后)是一个巨大的安全漏洞。

    你当前的胡椒方法要求每个用户通过轮换完全无效的密码,或等到他们下次登录轮换(可能永远不会)...

    这基本上使你的方法立即禁止。

  • 它需要您自己加密

    由于当前没有算法支持胡椒的概念,因此需要您编写算法或发明新算法以支持胡椒。如果你不能立即明白为什么那是一件非常糟糕的事情:

      

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

    永远滚动你自己的加密......

更好的方式

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

  • 只需使用存在的算法

    如果您正确使用bcrypt或scrypt(成本很高),除了最弱的字典密码之外的所有密码应该在统计上是安全的。成本为5的哈希bcrypt的当前记录是每秒71k哈希。按照这个速度,即使是6个字符的随机密码也需要数年才能破解。考虑到我的最低建议成本是10,这会使每秒的哈希值减少32倍。所以我们每秒只能说约2200个哈希值。按照这个速度,即使是一些字典短语或修改也可能是安全的。

    此外,我们应该在门口检查那些弱类密码而不允许它们进入。随着密码破解变得更加先进,密码质量要求也应该提高。它仍然是一个统计游戏,但通过适当的存储技术和强密码,每个人都应该非常安全......

  • 在存储之前加密输出哈希值

    安全领域中存在一种算法,用于处理我们上面所说的一切。它是分组密码。它很好,因为它是可逆的,所以我们可以旋转键(耶!可维护性!)。它很好,因为它按设计使用。这很好,因为它没有给用户任何信息。

    让我们再看看那一行。让我们说攻击者知道你的算法(这是安全所必需的,否则它是通过默默无闻的安全性)。使用传统的胡椒方法,攻击者可以创建一个哨兵密码,因为他知道盐和输出,他可以强制胡椒。好吧,这是一个长镜头,但它是可能的。使用密码,攻击者什么也得不到。由于盐是随机的,因此哨兵密码甚至无法帮助他/她。所以他们留下的最好的就是攻击加密的表格。这意味着他们首先必须攻击您的加密哈希以恢复加密密钥,然后攻击哈希。但是对于密码攻击的研究非常强烈,所以我们希望依赖它。

TL / DR

不要使用辣椒。它们存在许多问题,有两种更好的方法:不使用任何服务器端密码(是的,它没问题),并在存储之前使用块密码加密输出散列。

答案 1 :(得分:21)

我们应该谈谈胡椒的确切优势

  • 在特殊情况下,胡椒可以保护弱密码免受字典攻击,攻击者可以对数据库进行读访问(包含哈希),但无法访问胡椒源代码。

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

  • 每个密码的唯一盐
  • 慢速散列算法,如BCrypt

...强密码受到很好的保护。在这些条件下,即使已知盐,也几乎不可能强制使用强密码。问题是弱密码,它们是蛮力字典的一部分或是它们的派生。字典攻击会非常快速地显示这些,因为您只测试最常用的密码。

第二个问题是如何应用辣椒

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

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

还有另一种更好的方法:

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

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

答案 2 :(得分:2)

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

一般来说,尝试查找单个哈希的冲突很难(假设哈希是安全的)。但是,使用短哈希,可以使用计算机生成所有可能的哈希值,以查找到硬盘上。这被称为彩虹表。如果你创建一个彩虹表,那么你就可以进入这个世界并快速找到任何(未加盐的未加工的)哈希的可用密码。

辣椒的目的是使彩虹表能够破解您的密码列表。因此,在攻击者身上浪费更多时间来构建彩虹表。

然而,盐的目的是使每个用户的彩虹表对用户来说是唯一的,这进一步增加了攻击的复杂性。

计算机安全的关键几乎从来没有(数学上)不可能,只是在数学上和物理上都不切实际(例如在安全系统中,它会占用宇宙中的所有熵(以及更多)来计算单个用户的密码)。

答案 3 :(得分:2)

我希望这是关于盐和胡椒的讨论,而不是特定的算法,但我使用的是安全的

我所知道的每个安全密码散列函数都将密码和盐(以及秘密/胡椒粉,如果支持)作为单独的参数,并自行完成所有工作。

仅由于您正在连接字符串并且hash_function仅接受一个参数,我知道您并没有使用经过良好测试,分析得很好的标准算法之一,而是试图自己动手。不要那样做。

Argon2在2015年的密码哈希竞赛中获胜,据我所知,它仍然是新设计的最佳选择。它通过K参数(称为“秘密值”或“键”)支持Pepper。我知道没有理由不使用胡椒。最糟糕的是,Pepper会与数据库一起遭到破坏,并且您的状态不会比不使用它时还差。

如果您不能使用内置的胡椒支持,则可以使用this discussion中两个建议的公式之一:

Argon2(salt, HMAC(pepper, password))   or   HMAC(pepper, Argon2(salt, password))

重要说明:如果将HMAC(或任何其他哈希函数)的输出传递给Argon2(或任何其他密码哈希函数),请确保密码哈希函数支持嵌入的零字节,或者对哈希值进行编码(例如在base64中)以确保不存在零字节。如果您使用的语言的字符串支持嵌入的零字节,那么unless that language is PHP可能很安全,但是我还是会检查一下。

答案 4 :(得分:1)

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

如果黑客获得了您的数据库,他将能够开始强制您的用户密码。如果黑客能够破解一些密码,那么黑客就不会花很长时间来识别你的胡椒。