您在哪里存放盐串?


250

在对数据库存储的密码进行哈希处理时,我一直使用正确的按条目输入的盐字符串。出于我的需要,将盐存储在数据库中散列密码旁边一直很好。

但是,有些人建议将盐与数据库分开存储。他们的论据是,如果数据库遭到破坏,攻击者仍然可以构建一个彩虹表,并考虑到特定的盐字符串,以便一次破解一个帐户。如果该帐户具有管理员权限,那么他甚至不需要破解任何其他帐户。

从安全角度来看,将盐存储在其他位置是否值得?考虑在同一台计算机上具有服务器代码和数据库的Web应用程序。如果将盐类存储在该计算机上的平面文件中,则很有可能如果数据库遭到破坏,则盐类文件也会被破坏。

有什么建议的解决方案吗?


9
如果有一个地方可以存储攻击者无法获得的盐,那么您也应该只在其中存储密码。但是,为什么不对每个密码使用不同的盐?
jrockway

8
他为每个密码(jrockway)使用了不同的盐。
琥珀色

9
你的盐多少钱?您的盐应该足够大(32位?),以至于几乎没有机会为它预先计算过彩虹表。
M. Dudley

如今,@ emddudley一直习惯于使用64位整数作为盐,但没有理由我不能将它们延长。
Friedo

10
PWDTK的作者在此处sourceforge.net/projects/pwdtknet,说实话,我不会担心,我只将盐和密码存储在同一数据库中。无论如何,您始终应该假设盐是攻击者已知的,因此您的重点应该放在使用大型加密随机盐和执行足够的密钥拉伸(PBKDF2中的迭代)上,这样就不可能为一个已知的盐制作一个彩虹表都是不可行的。老实说,您试图通过在其他地方加盐来实现的目的是“通过隐蔽性实现安全性”,并且当您看到可能会发生故障的其他服务器之类的东西时,通常没有任何好处。
thashiznets

Answers:


259

彩虹表的要点在于,它们是预先创建的,并且可以批量分发,以节省其他人的计算时间-动态生成彩虹表所需的时间与直接破解密码+盐组合所需的时间一样长(因为实际上,在生成彩虹表时正在执行的操作是在对哈希进行强行的预运行),因此,通过了解盐可以有人“生成彩虹表”这一说法是虚假的。

只要将盐存储在单独的文件中,就没有真正意义,只要它们是基于每个用户的-盐的目的只是为了使其成为一个彩虹表而不会破坏数据库中的每个密码。


17
同意 您通过单独存储盐来防范的威胁模型是,用户可以以某种方式通过恶意手段访问数据库中的盐,但不能通过哈希(数据库中的哈希)来访问盐。假设该人稍后可以找到哈希,那么该人将提前开始计算彩虹表。捍卫这种单一攻击途径并非没有可能,但也不值得进行工程上的努力。
汤姆里特

好的帖子,我想知道同样的事情。我从来没有想过每位用户都吃盐,我一直认为一种盐对所有用户都有效。如何将盐存储为App Server加载的XML文件呢?还是以某种方式硬编码到servlet中?
jigzat

9
@Jigzat-如果您没有为每个用户单独添加盐,则盐化毫无意义。盐的重点是使每个用户密码的哈希散列成为一个单独的任务;如果所有人的盐都一样,那不是事实。
2012年

3
@TomRitter那不是唯一的情况。您假设所有密码都很复杂。一些攻击者可能会撒些盐和哈希,仅检查10,000个最常用的密码。这样,他们将获得相当数量的人。但是,如果他们无权使用盐,那类似于具有更长而更安全的密码的用户。现在,盐数据库在密码数据库被盗时保持安全的可能性有待讨论,但这是一个单独的问题。
chacham15年

@琥珀,我相信TomRitter是正确的。单独存储盐意味着强制攻击者使用蛮力攻击与更容易的字典攻击之间的区别。如果您知道盐,则可以在运行mill字典攻击时将其附加。如果您可以100%保卫自己的盐,则可以简单地使用相同的盐来强制攻击者暴力破解所有内容(即使对于使用“密码”作为其密码的用户)。但是你能捍卫自己的盐吗……可能不会。因此,也可以通过将其存储在散列旁边并执行更严格的密码规则来减少故障点。
Ultratrunks

35

我将对此提供稍微不同的看法。

我总是将盐和盐密码散列存储在一起。

例如,我将盐的前半部分放在密码的哈希值之前,并将盐的后半部分放在密码的哈希值之后。应用程序知道此设计,因此可以获取此数据,并获取salt和salted-password哈希。

我对这种方法的理由是:

如果密码/哈希数据被泄露并落入攻击者的手中,那么攻击者将无法通过查看数据来了解盐分。这样,攻击者实际上无法执行蛮力攻击来获取与哈希匹配的密码,因为他不知道哈希开头,也无法知道数据的哪些部分是盐的一部分,或者Salted-Password哈希的一部分(除非他确实知道您应用程序的身份验证逻辑)。

如果salted-password哈希按原样存储,则可以执行蛮力攻击以获得密码,该密码在salted和hashed时产生与salted-password哈希相同的数据。

但是,例如,即使salted-password哈希按原样存储,但预先添加了一个随机字节,只要攻击者不知道该第一个字节将被丢弃,这也将增加难度攻击。您的应用程序在用于验证用户身份时会知道丢弃数据的第一个字节。

结论到此。

1)切勿以正确的形式存储身份验证应用程序使用的数据。

2)如果可能,请对身份验证逻辑保密,以提高安全性。

再往前走一步

如果您不能对应用程序的身份验证逻辑保密,那么很多人都知道您的数据如何存储在数据库中。并假设您已决定将盐密码哈希与盐混合在一起存储,其中一些盐位于盐密码哈希之前,其余盐则附加在盐密码哈希之后。

生成随机盐时,您还可以随机决定在盐密码散列之前/之后将存储多少盐。

例如,您生成512字节的随机盐。您将盐附加到密码中,并获取盐密码的SHA-512哈希。您还会生成一个随机整数200。然后存储salt的前200个字节,然后存储salted-password哈希,然后存储salt的其余部分。

在验证用户的密码输入时,您的应用程序将越过字符串,并假设数据的前1个字节是salt的前1个字节,然后是salted哈希。此通行证将失败。应用程序将继续使用数据的前2个字节作为salt的前2个字节,并重复执行直到将前200个字节用作salt的前200个字节后找到肯定的结果。如果密码错误,应用程序将继续尝试所有排列,直到找不到为止。

这种方法的优点:

增强的安全性-即使您的身份验证逻辑已知,确切的逻辑在编译时也是未知的。即使知道确切的逻辑,实际上也无法执行暴力攻击。加盐长度将进一步提高安全性。

这种方法的缺点:

由于在运行时可以推断出确切的逻辑,因此这种方法非常占用CPU。盐的长度越长,此方法将占用更多的CPU。

验证不正确的密码将涉及最高的CPU成本。这可能会对合法请求产生反效果,但会提高针对攻击者的安全性。

该方法可以以多种方式实现,并且可以通过使用可变宽度的盐和/或盐腌密码哈希来使其更加安全。


9
使用您的方法,您只是在哈希过程(应用盐的算法)中添加了秘密。我想在本教程中指出这一秘密,在盐中加胡椒粉可以使添加起来容易得多。诸如BCrypt之类的现代哈希函数将在每次迭代中使用原始盐单独应用盐,因此无论如何您都无法对此进行控制。
martinstoeckli

@martinstoeckli虽然您正确地认为BCrypt可以单独应用盐,但是盐+哈希的存储权取决于开发人员。因此,您可以轻松地将椒盐添加到salt + hash中并将其持久保存到数据库中。然后,在随后的检索中,您从数据库中读取了该值,剥离了Pepper值,并将剩余的值传递给BCrypt。
PeterToTheThird

2
@PeterToTheThird-这将否定辣椒的优势。胡椒添加了服务器端的秘密,并且只有在秘密(与盐相反)的情况下才起作用。一种典型的攻击是SQL注入,当有人获得对数据库的访问权而不是对代码的访问权时,存储在数据库中的Pepper将变得毫无用处。大多数BCrypt实现都会将盐自动添加到结果哈希值中,因此该值已经包含盐,成本因子,算法和哈希。该字符串可以存储在长度为60个字符的单个字段中。
martinstoeckli

另外,在使用“密钥加强”功能(例如BCrypt)时,您无法控制盐的使用。但是,如果您想使用胡椒粉,则只需将胡椒粉添加到盐中,然后将其用作“胡椒粉”,以代替散列函数的“盐”输入。然后,“胡椒粉”是一条合适的数据,它存储在数据库中,而是嵌入在身份验证代码中,或存储在另一个安全位置。我从一般的角度解决了这个问题,使用SHA-512作为示例函数,但是BCrypt等也可以类似的方式使用。
Ibraheem

2
@martinstoeckli-是的,实际的实现取决于您使用的哈希函数。显然,在实现身份验证逻辑时,您需要考虑哈希函数的参数和输出。最终,辣椒只是引入你的散列函数,即另一个变量存储在相同的位置盐和哈希值。
Ibraheem

23

通常,它们会放在哈希之前,并存储在同一字段中。

无需单独存储它们-关键是为每个密码使用随机的盐,这样就无法针对整个密码哈希集使用单个Rainbow表。使用随机盐,攻击者必须单独对每个哈希进行暴力破解(或为所有可能的盐计算一个彩虹表-要做的工作更多)。

如果您有一个更安全的存储位置,则仅将哈希存储在该位置就很有意义。


4
但是,如果所有散列密码(包括其匹配的盐)都泄漏了怎么办?那不安全吗?
mghaoui 2012年

10
@mghaoui但是,如果您想知道“密码”,则仍然必须为每种盐构造一个Rainbow Table,除非某些盐相同。
富兰克林

4

基于William Penberthy撰写的《开发ASP.NET MVC 4 Web应用程序》:

  1. 要访问存储在单独数据库中的盐,需要黑客入侵两个不同的数据库才能访问盐和盐密码。将它们存储在与密码相同的表中,甚至存储在同一数据库的另一个表中,这意味着当黑客获得对数据库的访问权限时,他们将可以同时访问salt和密码哈希。由于安全性包括使黑客入侵系统过于昂贵或耗时以至于不值得的过程,因此使黑客必须获得的访问量加倍将使系统更加安全。
  2. 易于使用是将盐与哈希密码保存在同一数据库中的主要原因。您不必确保两个数据库始终同时可用并且始终保持同步。如果每个用户都随机分配一个盐,则拥有盐的好处是最小的,因为尽管这可能会使个人密码的发现更加容易,但破解整个系统密码所需的全部力量将很大。在这一级别的讨论中,这实际上是期望:保护密码。如果黑客获得了数据库的副本,则您的应用程序数据已经受到破坏。在这一点上,问题是要减轻用户的风险,因为有可能共享密码。
  3. 维护两个单独的链接数据库的要求非常广泛。当然,它增加了对安全性的认识,但是它提供的唯一好处是它可以保护密码,即单个数据元素。如果数据库中的每个字段都经过单独加密,并且使用了相同的方式,那么将其与数据分开存储会更有意义,因为可以增强系统的基本安全性。

但是,如果应用程序可以同时对两个数据库进行身份验证,那么如果攻击者破坏了应用程序代码,它是否与一个数据库基本相同?
约翰·欧内斯特

0

加盐的目的是使所有彩虹表都无用,并需要制作一组新的彩虹表。 猜测字符串和制作彩虹表所需的时间一样长。 例如,“ password”的SHA-256哈希为5e88 4898 da28 0471 51d0 e56f 8dc6 2927 7360 3d0d 6aab bdd6 2a11 ef72 1d15 42d8。添加盐后,例如“ badpassword”,要散列的新字符串为“ passwordbadpassword”,由于雪崩效应,该字符串将输出显着更改为457b f8b5 37f1 802e f9c8 2e46 b8d3 f8b5 721b 7cbb d485 f0bb e523 bfbe 73e6 58d6

通常,salt仅与密码存储在同一数据库中,这还因为如果一个数据库被黑客入侵,则另一个数据库也可能也会被盗。

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.