隐藏哈希中的盐的必要性

111

在工作中,我们有两种关于盐的竞争理论。我所从事的产品使用类似用户名称或电话号码之类的东西来为哈希生成器加盐。实质上,每个用户都不同但对于我们来说很容易获取。另一个产品为每个用户随机生成一种盐,并在用户更改密码时更改它。然后在数据库中加密这个盐。

我的问题是,第二种方法真的必要吗?从纯理论角度来看,我可以理解它比第一种方法更安全,但从实用角度来看呢?现在,要认证一个用户,必须解密盐并应用于登录信息。

经过思考,我并没有看到这种方法的真正安全收益。即使攻击者知道如何快速确定每个账户的盐,仍然将盐从一个账户更改到另一个账户,即使找到正确的哈希也会变得非常困难。这建立在密码足够强大的假设下。(显然,在所有密码都是两位数的情况下,找到一组密码的正确哈希值要比找到所有8位数密码的正确哈希值容易得多)。我的逻辑是错误的吗,还是我漏掉了什么东西?

编辑:好的,这就是为什么我认为加密盐很无意义的原因(让我知道我是否正确)。

为了说明问题,我们假设密码始终为8个字符,盐为5个字符,并且所有密码都由小写字母组成(这只是使数学更容易)。

每个条目都有不同的盐,这意味着我无法使用相同的彩虹表(实际上从技术角度来看如果我拥有足够大的彩虹表是可以的,但让我们暂时忽略这一点)。据我所了解,这正是盐的真正关键,因为要破解每个帐户,我必须为每个帐户重新发明密码破解方法。如果我知道如何将正确的盐应用于密码以生成哈希值,我会这样做,因为盐只是扩展了哈希短语的长度/复杂性。所以,我将需要生成的“知道”我有密码+盐的可能组合数量从13 ^ 26减少到8 ^ 26,因为我知道盐是什么。现在这使它更容易,但仍然非常困难。
接下来是加密盐。如果我知道盐已经加密,我就不会先尝试解密它(假设我知道它具有足够的加密级别)。我会忽略它。回到前面的例子,我将生成一个包含所有13 ^ 26键的更大的彩虹表。不知道盐肯定会减慢我的速度,但我认为它并没有增加尝试首先破解盐加密的巨大任务。这就是为什么我认为这不值得的原因。你有什么想法?
这里有一个链接,描述了在蛮力攻击下密码能够保持多长时间: http://www.lockdown.co.uk/?pg=combi

您不需要忽略相当大的彩虹表 - 因为该表也使得加密盐无效,因为它可以解密加盐哈希并再次用于解密原始哈希。好消息是,创建该表可能需要数个世纪。 - tloach
让我困惑的是,我并不完全确定那么大的彩虹表需要花费那么长时间来创建。这里有一个疯狂的想法,使用像Kraken这样的分布式计算平台(实际上就是这样)来生成它。那么需要多长时间呢? - kemiller2002
3
@Kevin:SHA1返回一个40个字符的十六进制字符串,所以有40^16个可能的返回值。假设单台计算机每秒可以计算1000个哈希值,我计算出需要1,000,000台计算机大约需要10亿年才能生成一个能够确定这样大小的字符串的彩虹表。 - tloach
+1,好问题,你很有见识。我认为你对这个问题的答案是错误的。密码应该始终保密,因为哈希值在获取之前无法被破解。你应该阅读关于CWE-760的内容(http://cwe.mitre.org/data/definitions/760.html)。 - rook
1
@tloach 有一些软件可以处理峰值达到5600M/s的MD5散列和2300M/s的SHA1散列。http://golubev.com/hashgpu.htm - Franklin
10个回答

107
隐藏盐是不必要的。
每个哈希应该使用不同的盐。实际上,通过从加密质量的随机数生成器获取8个或更多字节来实现这一点非常容易。
来自我之前的答案
盐值可以帮助防范预先计算的字典攻击。
假设攻击者有一个可能密码列表。他可以对每个密码进行哈希,然后将其与受害者密码的哈希进行比较,看是否匹配。如果列表很大,这可能需要很长时间。他不想在下一个目标上花费那么多时间,因此他记录了一个“字典”,其中哈希指向其相应的输入。如果密码列表非常非常长,他可以使用像彩虹表之类的技术来节省一些空间。
但是,假设他的下一个目标使用了盐值加密他们的密码。即使攻击者知道盐值是什么,他预先计算的表也毫无用处——盐值会更改每个密码所产生的哈希值。他必须重新对列表中的所有密码进行哈希,并将目标的盐值附加到输入中。每种不同的盐值都需要一个不同的字典,如果使用足够多的盐值,攻击者将没有足够的空间来存储它们所有的字典。为了节省时间而交换空间已经不再是一个选项;攻击者必须回到对每个要攻击的目标的列表中的每个密码进行哈希的方式。
因此,保持盐值秘密并不是必要的。确保攻击者没有与该特定盐值相对应的预先计算的字典就足够了。

经过进一步思考,我意识到自欺欺人地认为盐可以隐藏是危险的。更好的做法是假设盐无法隐藏,并设计系统以在这种情况下保持安全。我在另一个答案中提供了更详细的解释。


然而,NIST最近的建议鼓励使用一个额外的秘密“盐”(我见过其他人将其称为额外的秘密“胡椒粉”)与密码一起进行密钥派生的另一个迭代。这个迭代并不是为了增强防御预先计算的查找攻击,而是像一个好的密钥派生函数中的大量迭代一样,用于保护密码猜测。如果将此秘密与散列密码一起存储,则该秘密没有任何作用;必须将其作为秘密进行管理,在大型用户数据库中可能会很困难。

2
隐藏盐是必要的,因为在获得盐之前无法破解哈希。这与CWE-760有关(http://cwe.mitre.org/data/definitions/760.html)。 - rook
32
你误解了那个问题。它指的是使用可预测的盐。它并没有说要保密盐。事实上,如果你不用另一个密码进行保密,你几乎无法保密盐……这种情况下,为什么不把第二个密码作为盐呢?使用用户名作为盐是不好的,因为很可能有多个系统共享相同的用户名,这使得建立特定盐的表格更有价值。最好使用随机盐,但不需要保密。 - erickson
4
@erickson,我认为你在这里混淆了术语。除非隐藏盐值,否则盐值不会防止字典攻击。许多盐值是公开存储的。如果您知道盐值,您的字典攻击只会因附加盐值到字典条目所需的时间而变慢 :) 盐值可以防止彩虹表查找...这些查询相当快速。如果攻击者知道您的盐值,则无法保护您免受字典攻击。但是,如果攻击者不知道您的盐值,则可以保护您免受字典攻击,他们必须使用暴力攻击。 - Ultratrunks
4
@Ultratrunks 是的,我已经澄清了关于这个话题的一些回答,使用术语“预存储字典攻击”。比彩虹表更通用,它指的是任何允许使用哈希作为密钥进行反向查找明文的结构。无论你选择哪些术语,我的解释都明确说明盐的目的是为了打败彩虹表和类似机制。你应该总是假设攻击者知道盐值。如果可以保密,就不需要对密码进行散列处理。 - erickson
1
@stewSquared "必要"是一个强烈的词,我认为人们将它与"有用"区分开来。我认为读者会理解这里的"必要"意味着"盐必须具有一定的作用",而"不必要"则表示盐可以有一个作用而不隐藏它,这正是这个回答所说的。如果问题是"是否有必要称量蛋糕配料?",回答"不必要"将被理解为您可以不称量配料就能烤出蛋糕,而不是表示称量配料根本没有任何作用。 - cesoid
显示剩余6条评论

48

在这里需要考虑的是,您真正希望保护什么?如果某人可以访问您的数据库,则他们可以访问加密盐,并且很可能也可以访问您的代码。在这种情况下,他们能否解密加密盐?如果可以,那么加密就基本上没有用了。盐的真正作用在于,防止出现彩虹表攻击,以便一次性破解您的整个密码数据库。从这个角度来看,只要每个盐都是唯一的,就没有区别,无论是对于每个密码单独使用您的盐还是加密后的盐都需要进行暴力破解攻击。


有点陌生这些概念,所以问题可能看起来很幼稚,但是如果知道每个密码的盐值,用一个组合尝试所有可能的密码和盐值不会更容易生成那张彩虹表吗? - stdout
彩虹表从1000个常用密码中破解起来几乎和哈希速度一样快。唯一的办法是假设您的密码分布是均匀的...而我们知道它们并不是。 - DaWNFoRCe
不,他们很可能没有同时访问数据库和源代码的权限,源代码也不应该包含用于加密的应用程序秘钥。考虑SQL注入攻击向量或暴露的备份数据库。这些都不会授予对代码或加密密钥的访问权限。 - stewSquared
1
我同意stewSquared的观点,拥有数据库并不意味着拥有代码。同样,拥有代码并不意味着拥有加密密钥。如果你删除这些陈述,我认为你的回答相对于其他回答来说是不错的,因为它迅速地指出了重点,即如果你试图防止彩虹表攻击,盐值并不需要被隐藏。 - cesoid

7
一个隐藏的pepper不再是盐。它有它的用途。与盐不同。
Pepper是一种秘密密钥,添加到密码+盐中,使哈希成为HMAC(基于哈希的消息认证码)。一个黑客如果能够访问哈希输出和盐,理论上可以暴力破解猜测一个输入,这将生成哈希(因此在密码文本框中通过验证)。通过添加pepper,您以加密随机方式增加了问题空间,使问题无法在没有严重硬件的情况下不可解决。
有关pepper的更多信息,请查看这里
另请参见hmac

4
... 例如用户名或电话号码来对哈希进行加盐处理。...我的问题是第二种方法真的有必要吗?我可以从纯理论的角度理解它比第一种方法更安全,但是从实用性的角度来看呢?
从实用的角度来说,加盐是一个实现细节。如果您曾经更改过用户信息的收集或维护方式 - 并且用户名称和电话号码有时会更改,正如您的例子所示 - 那么您可能已经危及了安全性。您是否希望这样一个外向的变化具有更深层次的安全问题?
停止要求每个帐户都需要电话号码是否需要涉及完整的安全审查,以确保您没有将这些帐户开放给安全威胁?

3
更不用说,如果您正在使用某些随意的用户信息,当他们更改该信息时,您需要让他们再次输入密码,以便您可以再次使用新盐加密它。 - Treborbob

3

我理解的“盐”是它可以使破解更加困难,但它并不试图隐藏额外的数据。如果您试图通过使盐“保密”来获得更多安全性,则实际上只需要在加密密钥中使用更多位。


3
第二种方法只比第一种稍微安全一点。盐可以保护用户免受字典攻击和彩虹表攻击,使得野心勃勃的攻击者更难以破坏您的整个系统,但仍然容易受到针对系统中一个用户的攻击。如果您使用公开可用的信息(如电话号码),并且攻击者意识到这一点,则您已经为他们的攻击节省了一步。当然,如果攻击者获得了您的整个数据库,包括盐在内,那么这个问题就没有意义了。
编辑:重新阅读这篇答案和一些评论后,我意识到一些混淆可能是由于我只比较了问题中提出的两种非常具体的情况:随机盐和非随机盐。如果攻击者获得了您的整个数据库,使用电话号码作为盐的问题就没有意义了,而不是根本不使用盐的问题。

他们如何防范字典攻击? - tloach
通过强制攻击者为每个密码+盐的组合创建一个新的字典表,可以有效防止利用字典攻击破解。如果没有盐值,一个字典表就可以用于攻击您的所有密码。 - Bill the Lizard
当然,如果攻击者获取了您的整个数据库,包括所有的盐,那么这个问题就没有意义了。这不是盐被加密的原因吗? - Patrick McElhaney
2
@Bill:你刚刚描述了一个彩虹表。字典攻击是我使用普通单词尝试进行身份验证。这是一种暴力破解,但答案空间大大缩小。没有哈希能够抵御暴力破解。 - tloach
我从未听说过这种做法,但我不是安全专家。似乎加密唯一的盐可以增加对彩虹表攻击的额外保护层。 - Bill the Lizard
@tloach:我不明白你的观点。哈希和加盐通过强制攻击者使用暴力破解来进行防御。这是一个吸引人的特性。 - Bill the Lizard

2
这里有一个简单的例子,展示了为什么对于每个哈希值使用同样的盐是不好的:
考虑下面的表格:
UserId  UserName,   Password
     1  Fred       Hash1 =  Sha(Salt1+Password1)    
     2  Ted        Hash2 =  Sha(Salt2+Password2)    

情况1:当salt1与salt2相同时 如果将Hash2替换为Hash1,则用户2可以使用用户1的密码登录。

情况2:当salt1与salt2不同时 如果将Hash2替换为Hash1,则用户2无法使用用户1的密码登录。


我们不会为每个账户使用相同的哈希值,而是为每个哈希值使用相同类型的信息。例如,一个账户的盐值是该账户的电话号码等。 - kemiller2002
我知道这已经过了很长时间,但是...你不能依靠盐来保护免受此类攻击。我们必须假设攻击者除了秘密(即密码)之外,对认证系统的一切都了如指掌。因此,我们必须假设攻击者知道a)我们使用什么作为盐(大多数情况下,这是以明文形式存储在同一数据库和表中的),以及b)我们如何使用盐进行哈希(即附加、哈希两次等)。如果用户有能力切换哈希,则我们必须假设他们也可以切换盐。在这种情况下,盐是无用的。 - Dave Satch

1

有两种技术,目标不同:

  • “盐”用于使两个本来相等的密码加密方式不同。这样,入侵者无法有效地对整个加密密码列表进行字典攻击。

  • 在哈希消息之前添加(共享的)“秘密”,以便入侵者无法创建自己的消息并被接受。


0

我倾向于隐藏盐。在哈希密码之前,我使用10位盐,将1到1024的随机数添加到密码开头。当比较用户输入的密码和哈希值时,我循环从1到1024,并尝试每个可能的盐值,直到找到匹配项。这需要不到1/10秒的时间。我从PHP password_hashpassword_verify 中得到了这种做法的灵感。在我的示例中,“成本”为10,表示10位盐。或者根据另一个用户所说,隐藏的“盐”称为“胡椒粉”。盐没有在数据库中加密。它被暴力破解出来。这将使彩虹表必须反转哈希1000倍。我使用sha256,因为它快速且仍被认为是安全的。


所以,如果我的密码是“345678”,而你在前面添加的随机盐巧合地是“12”。如果有人输入“45678”作为我的密码。这在许多方面都是错误的。 - Yurippenet
我猜 Russell Hankins 的意思是在左侧加上从1到1024的随机数,并用零进行格式化;也就是说,如果随机盐是12,则在前面添加“0012”。 - mayeulk

-1

实际上,这取决于您试图保护数据的攻击类型。

为每个密码使用唯一的盐的目的是防止针对整个密码数据库的字典攻击。

加密每个密码的唯一盐会使破解单个密码更加困难,但您必须权衡是否真的有多大的好处。如果攻击者通过暴力破解找到了这个字符串:

Marianne2ae85fb5d

将哈希值与存储在数据库中的哈希值进行比较,是很难分辨哪部分是密码,哪部分是盐的吗?


2
如果有人暴力破解一个无法猜测的密码,我想你已经完了,因为显然他们拥有的技术是没有人想到过的。 - Instance Hunter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接