关于安全性:最佳实践:Salting&

Best Practices: Salting & peppering passwords?

我遇到了一个讨论,在讨论中我发现我所做的并不是加盐密码,而是加盐密码,从那时起我就开始使用类似以下的功能:

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

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

  • salt是一个随机生成的值,通常与字符串一起存储在数据库中,目的是使不可能使用哈希表破解密码。由于每个密码都有自己的salt,因此必须逐个强制它们,才能破解它们;但是,由于salt与密码哈希一起存储在数据库中,数据库折衷意味着两者都会丢失。

  • Pepper是一个站点范围的静态值,与数据库分开存储(通常在应用程序的源代码中进行硬编码),这是为了保密。它的使用是为了让数据库的折衷不会导致整个应用程序的密码表是可强制执行的。

是否有我丢失的东西,加盐和灌输我的密码是保护我的用户安全的最佳选择?这样做有什么潜在的安全缺陷吗?

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


好啊。既然我需要一遍又一遍地写这篇文章,我将只做最后一个关于胡椒粉的标准答案。好的。辣椒的明显优点

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

这就是为什么这么多人相信辣椒是个好主意。这"有道理"。好的。辣椒的现实

在安全和密码学领域,"合理"是不够的。一些事情必须被证明是有意义的,以便被认为是安全的。此外,它必须以可维护的方式实现。无法维护的最安全的系统被认为是不安全的(因为如果该安全的任何部分崩溃,整个系统就会崩溃)。好的。

辣椒既不符合可证明的模式,也不符合可维护的模式…好的。辣椒的理论问题

既然我们已经准备好了,让我们来看看辣椒有什么问题。好的。

  • 将一个哈希值输入另一个哈希值是危险的。好的。

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

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

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

    重点是,虽然这不是什么大问题,但仅仅是扔东西也不是一件小事。加密系统的设计是为了避免"应该工作"的情况,而将重点放在"设计工作"的情况上。好的。

    虽然这似乎纯粹是理论上的,但事实上并非如此。例如,bcrypt不能接受任意密码。因此,如果hash()返回二进制字符串,那么传递bcrypt(hash(pw), salt)确实会导致比bcrypt(pw, salt)弱得多的哈希。好的。

  • 反设计工作好的。

    bcrypt(和其他密码散列算法)的设计方法是使用salt。胡椒的概念从未被引入。这可能看起来很琐碎,但事实并非如此。原因是盐不是秘密。它只是一个攻击者可以知道的值。另一方面,根据定义,胡椒是一个密码秘密。好的。

    当前的密码散列算法(bcrypt、pbkdf2等)都设计为只接受一个秘密值(密码)。在算法中加入另一个秘密还没有被研究过。好的。

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

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

  • 复杂性是安全的敌人好的。

    信不信由你,复杂性是安全的敌人。使一个算法看起来很复杂可能是安全的,也可能不是。但它不安全的可能性非常大。好的。

辣椒的重大问题

  • 它不可维护好的。

    您对Peppers的实现排除了旋转Pepper键的能力。由于Pepper用于单向函数的输入,因此在该值的生命周期内永远不能更改Pepper。这意味着你需要想出一些奇怪的黑客来支持钥匙旋转。好的。

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

    而您当前的Pepper方法将要求每个用户要么将其密码完全无效,要么等到下一次登录Rotate为止(这可能永远不会发生)。好的。

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

  • 它要求你使用自己的密码好的。

    由于目前没有任何算法支持胡椒的概念,所以它要求您要么编写算法,要么发明新的算法来支持胡椒。如果你不能马上明白为什么这是一件非常糟糕的事情:好的。

    Anyone, from the most clueless amateur to the best cryptographer, can create an algorithm that he himself can't break.

    Ok.

    • 布鲁斯·施奈尔

    不要使用自己的密码…好的。

更好的方法

因此,在上面详细介绍的所有问题中,有两种方法可以处理这种情况。好的。

  • 只要使用现有的算法好的。

    如果正确使用bcrypt或scrypt(成本很高),那么除了最弱的字典密码之外,所有密码都应该在统计上是安全的。以5为代价散列bcrypt的当前记录是每秒71k个散列。以这种速度,即使是6个字符的随机密码也需要多年才能破解。考虑到我推荐的最低成本是10,这就将每秒的散列数减少了32倍。所以我们只讨论每秒2200个哈希。按这个速度,即使是一些字典短语或修饰语也可能是安全的。好的。

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

  • 存储前加密输出哈希好的。

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

    让我们再看一次那条线。假设攻击者知道您的算法(这是安全性所必需的,否则它是通过模糊来实现安全性的)。使用传统的Pepper方法,攻击者可以创建一个哨兵密码,因为他知道盐和输出,所以他可以对Pepper进行暴力破解。好吧,这是一个很长的机会,但这是可能的。有了密码,攻击者什么也得不到。因为salt是随机的,所以一个哨兵密码甚至不能帮助他/她。所以最好的办法就是攻击加密的表单。这意味着他们首先必须攻击加密哈希以恢复加密密钥,然后攻击哈希。但是对于密码的攻击有很多研究,所以我们要依赖它。好的。

TL/DR

不要用辣椒。它们有很多问题,有两种更好的方法:不使用任何服务器端机密(是的,没关系)和在存储之前使用块密码加密输出哈希。好的。好啊。


首先,我们应该谈谈胡椒的确切优势:

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

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

  • 每个密码的唯一盐
  • 像bcrypt这样的缓慢散列算法

…强密码受到良好保护。在这种情况下,即使知道salt,也几乎不可能强制强密码。问题是弱密码,这是蛮力字典的一部分,或者是它们的派生。字典攻击会很快发现这些密码,因为您只测试最常见的密码。

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

应用Pepper的一种常用方法是在将密码和Pepper传递给哈希函数之前将其组合在一起:

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

但还有另一种更好的方法:

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

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


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

一般来说,试图找到单个哈希的冲突是困难的(假设哈希是安全的)。但是,使用短哈希,可以使用计算机生成所有可能的哈希,以查找硬盘。这叫做彩虹桌。如果您创建了一个彩虹表,那么您就可以进入这个世界,快速找到任何(未加保护的)哈希的可重用密码。

胡椒的要点是使彩虹表需要黑客你的密码列表唯一。因此,在攻击者身上浪费更多的时间来构建彩虹表。

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

实际上,计算机安全的重点几乎永远不会使它(在数学上)不可能,只是在数学上和物理上不切实际(例如,在安全系统中,计算单个用户的密码需要宇宙中的所有熵(以及更多熵)。


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

如果黑客获取了你的数据库,他将能够开始暴力强迫你的用户密码。如果那个黑客破解了一些密码,他很快就能识别出你的胡椒粉。