最佳实践:Salting & Peppering 密码?
Posted
技术标签:
【中文标题】最佳实践:Salting & Peppering 密码?【英文标题】:Best Practices: Salting & peppering passwords? 【发布时间】:2013-05-29 07:23:46 【问题描述】:我遇到了一个讨论,在讨论中我了解到我所做的实际上并不是对密码进行加盐,而是对密码进行添加,并且从那时起我开始使用以下功能同时进行这两种操作:
hash_function($salt.hash_function($pepper.$password)) [multiple iterations]
忽略所选的哈希算法(我希望这是关于椒盐的讨论,而不是特定的算法,但我使用的是安全的算法),这是一个安全的选项还是我应该做一些不同的事情?对于那些不熟悉这些术语的人:
salt 是一个随机生成的值,通常与字符串一起存储在数据库中,旨在使使用哈希表无法破解密码。由于每个密码都有自己的盐,因此必须对它们进行单独的暴力破解才能破解它们;但是,由于盐与密码哈希一起存储在数据库中,因此数据库泄露意味着两者都丢失。
pepper 是一个站点范围的静态值,与数据库分开存储(通常在应用程序的源代码中硬编码),旨在保密。使用它是为了防止数据库受到破坏而导致整个应用程序的密码表被暴力破解。
我有什么遗漏吗?我的密码是否是保护用户安全的最佳选择?这样做有什么潜在的安全漏洞吗?
注意:为了讨论的目的,假设应用程序和数据库存储在不同的机器上,不共享密码等,因此数据库服务器的破坏并不意味着应用程序服务器的破坏。
【问题讨论】:
不是相当重复,但非常相关:***.com/questions/16594613/… 跨站重复:security.stackexchange.com/q/3272/2113 【参考方案1】:好的。鉴于我需要写这个over 和over,我将仅针对胡椒做最后一个规范答案。
辣椒的明显优势
很明显,辣椒应该使哈希函数更安全。我的意思是,如果攻击者只获取您的数据库,那么您的用户密码应该是安全的,对吧?看起来合乎逻辑,对吧?
这就是为什么这么多人认为辣椒是个好主意的原因。这说得通”。
辣椒的现实
在安全和密码学领域,“有意义”是不够的。某些东西必须是可证明的并且是有意义的,才能被认为是安全的。此外,它必须以可维护的方式实现。无法维护的最安全的系统被认为是不安全的(因为如果该安全性的任何部分发生故障,整个系统就会崩溃)。
辣椒既不适合可证明的模型,也不适合可维护的模型......
辣椒的理论问题
现在我们已经做好了准备,让我们看看辣椒有什么问题。
将一个哈希值输入另一个哈希值可能很危险。
在您的示例中,您执行hash_function($salt . hash_function($pepper . $password))
。
从过去的经验中我们知道,“仅将一个哈希结果输入”另一个哈希函数会降低整体安全性。原因是这两个哈希函数都可能成为攻击的目标。
这就是为什么像 PBKDF2 这样的算法使用特殊操作来组合它们(在这种情况下是 hmac)。
关键是,虽然这没什么大不了的,但随便扔也不是一件小事。加密系统旨在避免“应该工作”的情况,而是专注于“设计为工作”的情况。
虽然这看起来纯粹是理论上的,但实际上并非如此。例如,Bcrypt cannot accept arbitrary passwords。因此,如果hash()
返回二进制字符串,则传递bcrypt(hash(pw), salt)
确实会导致比bcrypt(pw, salt)
更弱的散列。
反对设计
bcrypt(和其他密码哈希算法)的设计方式是使用盐。辣椒的概念从未被引入。这似乎是一件小事,但事实并非如此。原因是盐不是秘密。它只是一个攻击者可以知道的值。另一方面,根据定义,辣椒是一种密码学的秘密。
当前的密码散列算法(bcrypt、pbkdf2 等)都设计为只接受一个秘密值(密码)。根本没有研究在算法中添加另一个秘密。
这并不意味着它不安全。这意味着我们不知道它是否安全。安全和密码学的一般建议是,如果我们不知道,那就不知道。
因此,在密码学家设计和审查算法以用于秘密值(辣椒)之前,当前的算法不应与它们一起使用。
复杂性是安全的敌人
信不信由你,Complexity Is The Enemy Of Security。制作一个看起来很复杂的算法可能是安全的,也可能不是。但是它不安全的可能性非常大。
辣椒的重大问题
这是不可维护的
您对辣椒的实现排除了旋转辣椒键的能力。由于胡椒用于单向函数的输入,因此您永远不能在值的生命周期内更改胡椒。这意味着你需要想出一些奇怪的技巧来让它支持密钥轮换。
这是非常重要的,因为它是您存储加密机密时所必需的。没有一种机制来轮换密钥(定期轮换,以及在违规之后)是一个巨大的安全漏洞。
而您当前的辣椒方法将要求每个用户要么通过轮换使他们的密码完全失效,要么等到他们的下一次登录轮换(可能永远不会)......
这基本上使您的方法立即不可行。
它要求你使用自己的加密货币
由于当前没有算法支持辣椒的概念,因此需要您编写算法或发明新的算法来支持辣椒。如果你不能立即明白为什么这是一件非常糟糕的事情:
Bruce Schneier任何人,从最无知的业余爱好者到最优秀的密码学家,都可以创建自己无法破解的算法。
永远不要使用自己的加密货币...
更好的方法
因此,在上面详述的所有问题中,有两种方法可以处理这种情况。
只使用现有的算法
如果您正确使用 bcrypt 或 scrypt(成本很高),那么除了最弱的字典密码之外,所有密码都应该在统计上是安全的。以成本 5 散列 bcrypt 的当前记录是每秒 71k 散列。以这种速度,即使是 6 个字符的随机密码也需要数年时间才能破解。考虑到我的最低推荐成本是 10,这将每秒哈希值减少了 32 倍。所以我们只会谈论每秒 2200 个哈希值。按照这个速度,即使是一些字典短语或修饰语也可能是安全的。
此外,我们应该在门口检查那些弱密码类别,不允许他们进入。随着密码破解越来越先进,密码质量要求也应该如此。它仍然是一个统计游戏,但有了适当的存储技术和强大的密码,每个人都应该非常安全......
在存储之前加密输出哈希
在安全领域中存在一种算法,旨在处理我们上面所说的一切。这是一个分组密码。这很好,因为它是可逆的,所以我们可以旋转密钥(耶!可维护性!)。这很好,因为它按设计使用。这很好,因为它没有给用户任何信息。
让我们再看看那条线。假设攻击者知道您的算法(这是安全所必需的,否则它是通过晦涩难懂的安全性)。使用传统的辣椒方法,攻击者可以创建一个哨兵密码,并且由于他知道盐和输出,他可以暴力破解辣椒。好吧,这是一个很长的镜头,但它是可能的。使用密码,攻击者一无所获。而且由于盐是随机的,因此哨兵密码甚至对他/她没有帮助。所以他们剩下的最好的就是攻击加密的形式。这意味着他们首先必须攻击您的加密哈希以恢复加密密钥,然后再攻击哈希。但是有大量关于密码攻击的研究,所以我们希望依靠它。
TL/DR
不要使用辣椒。它们存在许多问题,有两种更好的方法:不使用任何服务器端机密(是的,没关系)以及在存储之前使用块密码加密输出哈希。
【讨论】:
感谢您包含加密哈希值的最后一部分,这是我完全同意的答案。如果加密将成为您的password api 的一部分,那么没有理由不使用它,所以也许......(我很乐意为它编写文档) @martinstoeckli:我不同意将加密步骤添加到简化的哈希 API。原因是秘密(密钥)的存储比人们意识到的要困难得多,而且很容易把自己放在脚上。对于 99.9% 的用户来说,除了最简单的密码之外,原始 bcrypt 已经绰绰有余了…… @ircmaxell - 另一方面,你不会失去任何东西。在最坏的情况下,当密钥已知时,攻击者仍然必须破解 BCrypt 哈希(与没有加密的情况相同)。这与存储用于加密数据的密钥不同,这是关于添加服务器端机密。只要攻击者无法控制服务器/代码,即使是硬编码的密钥也可以保护那些弱密码。这种情况并不少见:除了 SQL 注入之外,还有丢弃的备份、丢弃的服务器……都可能导致这种情况。许多 php 用户在托管服务器上工作。 @martinstoeckli 我在这里必须同意 ircmaxwell,我认为加密不属于密码 api。不过,可以注意到,为了最大程度地安全,加密您的哈希是可以使用的附加条款。 我被指向OWASP Application Security Verification Standard 4.0 第 2.4.5 节建议使用秘密盐(又名胡椒):“验证是否执行了密钥派生函数的额外迭代,使用的盐值是秘密,只有验证者知道。”【参考方案2】:首先我们应该谈谈辣椒的确切优势:
辣椒可以保护弱密码免受字典攻击,在特殊情况下,攻击者可以读取数据库(包含哈希值),但无权访问辣椒的源代码。典型的场景是 SQL 注入、丢弃的备份、丢弃的服务器……这些情况并不像听起来那么罕见,而且通常不受您的控制(服务器托管)。如果你使用...
每个密码唯一的盐 像 BCrypt 这样的慢速哈希算法...强密码受到很好的保护。在这些条件下,几乎不可能暴力破解强密码,即使知道盐。问题是弱密码,它们是暴力字典的一部分,或者是它们的派生词。字典攻击会很快发现这些密码,因为您只测试最常用的密码。
第二个问题是辣椒怎么涂?
一个经常推荐的应用辣椒的方法是在将密码和辣椒组合起来传递给哈希函数之前:
$pepperedPassword = hash_hmac('sha512', $password, $pepper);
$passwordHash = bcrypt($pepperedPassword);
还有另一种更好的方法:
$passwordHash = bcrypt($password);
$encryptedHash = encrypt($passwordHash, $serverSideKey);
这不仅允许添加服务器端密钥,还允许在必要时交换 $serverSideKey。此方法涉及更多工作,但如果代码曾经存在(库),则没有理由不使用它。
【讨论】:
所以你会说胡椒确实比盐更安全,简而言之?感谢您对如何实施的帮助。 @LightningDust - 是的,对于弱密码,只要辣椒保密。它可以缓解一些明确定义的威胁类型。 @martinstoeckli 绝对是实现这一点的好方法。很高兴看到有一些安全经验的人支持这种方法。 mysqlAES_ENCRYPT($passwordHash, $serverSideKey)
调用是否也是实现此功能的合适方式?
@Foo_Chow - 我不知道MySQL函数的实现,但似乎他们使用了EBC模式,以避免IV-vector。连同已知的明文(哈希值总是以相同的字符开头),这可能是一个问题。在我的homepage 上,我发布了一个示例实现,用于处理这种加密。
@martinstoeckli 有趣,对概念不太熟悉;然而,对于最稳健的结果,似乎需要 IV。似乎不会为额外的好处增加太多开销。【参考方案3】:
盐和胡椒的目的是增加预先计算的密码查找的成本,称为彩虹表。
一般来说,寻找单个哈希的冲突是很困难的(假设哈希是安全的)。但是,使用短散列,可以使用计算机生成所有可能的散列到硬盘上的查找中。这被称为彩虹表。如果你创建了一个彩虹表,你就可以走出去,快速找到任何(无盐无胡椒)哈希的合理密码。
胡椒的目的是使破解您的密码列表所需的彩虹表独一无二。从而浪费了攻击者更多的时间来构建彩虹表。
然而,加盐的目的是让每个用户的彩虹表对用户来说都是唯一的,从而进一步增加了攻击的复杂性。
实际上,计算机安全的重点几乎从不让它(数学上)不可能,只是在数学上和物理上不切实际(例如在安全系统中,它需要宇宙中的所有熵(以及更多)来计算单个用户的密码)。
【讨论】:
那么盐+胡椒比盐更安全吗?或者我最好还是放弃辣椒并运行更多的 scrypt 迭代? 彩虹表的主要特点是您不会为特定攻击创建一个,而是下载一个预先存在的。有很长的彩虹表可用于流行的哈希算法,只需 google 一下! @LightningDust 我自己想不出任何理由。然而,理查德在另一个线程中想出了一个。您可以在源代码中隐藏胡椒,这意味着攻击者需要访问的另一个地方,只是为了得到一张彩虹表。 @Aron - 这就是我的想法,因为我们的应用程序服务器与数据库服务器分开(也就是说,如果您在我们的数据库服务器上获得root
,您仍然无法访问我们的应用程序服务器),在源代码中(在我们的配置文件中)隐藏胡椒将提供额外的安全性。【参考方案4】:
我希望这是关于盐和胡椒的讨论,而不是特定的算法,但我使用的是安全算法
我所知道的每个安全密码散列函数都将密码和盐(以及秘密/胡椒,如果支持)作为单独的参数,并自行完成所有工作。
仅仅因为您正在连接字符串并且您的 hash_function
只接受一个参数这一事实,我知道您没有使用那些经过充分测试、充分分析的标准算法之一,而是试图滚动您的自己的。不要那样做。
Argon2 在 2015 年赢得了密码哈希竞赛,据我所知,它仍然是新设计的最佳选择。它通过 K 参数(称为“秘密值”或“密钥”)支持胡椒。我知道没有理由不使用胡椒粉。在最坏的情况下,辣椒会与数据库一起被破坏,而你的情况并不比你没有使用它更糟糕。
如果您不能使用内置的胡椒支持,您可以使用this discussion 中建议的两个公式之一:
Argon2(salt, HMAC(pepper, password)) or HMAC(pepper, Argon2(salt, password))
重要提示:如果您将 HMAC(或任何其他散列函数)的输出传递给 Argon2(或任何其他密码散列函数),请确保密码散列函数支持嵌入的零字节或对散列值进行编码(例如在 base64 中)以确保没有零字节。如果您使用的语言的字符串支持嵌入零字节,那么您可能是安全的,unless that language is PHP,但我还是会检查一下。
【讨论】:
【参考方案5】:看不到在源代码中存储硬编码值具有任何安全相关性。这是通过默默无闻的安全。
如果黑客获取了您的数据库,他将能够开始暴力破解您的用户密码。如果那个黑客设法破解了几个密码,他很快就会识别出你的辣椒。
【讨论】:
这将使未加盐密码表的预计算彩虹表无用。简而言之,即使攻击者知道你的辣椒,他也需要创建一个新的彩虹表。 它根据数据库中不可用的数据加强哈希,这是一件好事。数据库中的事物可能会在漏洞中暴露出来——代码中的值不太可能以相同的方式被访问。 Salts 是单向函数,即使成功地暴力破解密码也只会给你那个密码,并不能帮助你获得胡椒值本身。 @LightningDust 我认为您的意思是“哈希是陷门函数”。是的,不可能从安全哈希中找出你的盐和/或胡椒粉(实际上这是安全哈希的定义)。 @Aron Security Through Obscurity 可以作为一种有效的技术用作防御层。关键是它应该永远被用作防御,而是用来“减慢攻击者的速度”。如果不是这样,就不会使用蜜罐之类的东西。相反,我们可以通过隐蔽性有效地利用安全性来帮助减缓攻击者的速度,只要我们不依赖它来确保应用程序的安全性。以上是关于最佳实践:Salting & Peppering 密码?的主要内容,如果未能解决你的问题,请参考以下文章