密码哈希的非随机盐


89

更新:我最近从这个问题中学到,在下面的整个讨论中,我(而且我相信其他人也这样做)有点令人困惑:我一直称其为Rainbow表的实际上是一个哈希表。彩虹桌是更复杂的生物,实际上是Hellman哈希链的变体。尽管我相信答案仍然是相同的(因为它不能归结为密码分析),但其中的某些讨论可能有些偏斜。
问题是:“ 什么是彩虹桌?如何使用它们?


通常,我总是建议使用加密强度高的随机值作为盐,与哈希函数(例如,密码)配合使用,例如,防止Rainbow Table攻击。

但是,实际上在密码学上盐必须是随机的吗?在这方面,任何唯一值(每个用户唯一,例如userId)是否足够?实际上,这将防止使用单个Rainbow Table破解系统中的所有(或大多数)密码...
但是缺乏熵真的会削弱哈希函数的加密强度吗?


注意,我不是在问为什么使用盐,如何保护它(不需要),使用单个常量哈希(不要)或要使用哪种哈希函数。
只是盐是否需要熵。


到目前为止,感谢所有人提供的答案,但我想重点介绍一下我不太熟悉的领域。对密码分析的主要影响-如果有人从密码数学PoV中获得一些输入,我将不胜感激。
另外,如果还没有考虑其他向量,那也是很好的输入(请参阅多个系统上的@Dave Sherohman点)。
除此之外,如果您有任何理论,想法或最佳实践,请提供证明,攻击场景或经验证据作为支持。甚至是可以接受折衷的合理考虑...我对这个问题的最佳实践(B资本P大写)很熟悉,我想证明这实际上提供了什么价值。


编辑:这里有一些非常好的答案,但是我认为正如@Dave所说的,归结于Rainbow Tables的常见用户名...以及可能不太常见的名称。但是,如果我的用户名是全局唯一的怎么办?对于我的系统而言,不一定是唯一的,但对于每个用户而言,例如,电子邮件地址。
没有动力为单个用户建立RT(正如@Dave所强调的那样,salt不会保密),并且这仍然可以防止群集。唯一的问题是,我在不同的站点上可能拥有相同的电子邮件和密码-但无论如何,萨尔特不会阻止它。
因此,可以归结为密码分析-是否需要熵?(我目前的想法是,从密码分析的角度来看这不是必需的,但是从其他实际原因出发。)


我必须说,我对以下许多答案感到困惑。使用盐的主要目的只是为了防止彩虹表攻击,因此用户应做的任何事情都应做,因为它迫使攻击者为每种盐重新创建彩虹表。我的2c。
Goran,2009年

如果需要盐,例如。网站上,您通常在网址中包含ID。如果攻击者知道(并且我们假设他确实如此),则密码salt是用户ID +用户名,那么修改攻击以避免SA值很容易。
dmajkic,2009年

@dmajkic,salt旨在防止RT攻击并为不同用户区分相同的密码。这是给定的,即使使用用户名也是如此。
AviD 2009年

@AviD:是的。但是,如果我知道我的通行证的哈希值,并且我知道salt是我的用户名,那么我可以轻松地为任何词典单词创建哈希化的通行值,并将其与其他人的哈希值进行比较。这就是为什么时间比用户名更好的原因。
dmajkic,2009年

1
刚刚在PHP Security Consortium网站上找到了一篇文章,该文章在示例中使用md5哈希随机数作为盐 phpsec.org/articles/2005/password-hashing.html
helloworlder

Answers:


156

传统上,Salt是作为哈希密码的前缀存储的。这已经使任何有权访问密码哈希的攻击者都知道。使用用户名是否为salt不会影响该知识,因此不会对单系统安全性产生影响。

但是,将用户名或任何其他用户控制的值用作salt会降低跨系统安全性,因为在多个使用相同密码哈希算法的系统上具有相同用户名和密码的用户最终将在每个系统。我认为这不是重大责任,因为作为攻击者,我将在尝试以其他方式破坏帐户的方式之前,先尝试使用已知已在其他系统上使用的目标帐户的密码。相同的哈希只会事先告诉我已知的密码会起作用,它们不会使实际的攻击变得更容易。(不过,请注意,对帐户数据库进行快速比较会提供更高优先级的目标列表,因为它会告诉我谁是谁以及谁在不使用密码。)

这种想法带来的更大危险是,通常会重复使用用户名-例如,几乎您希望访问的任何站点都会有一个名为“ Dave”的用户帐户,而“ admin”或“ root”更为常见-这会使以这些通用名称为目标用户的彩虹表的构建更加容易和有效。

这两个漏洞都可以通过在对哈希值进行哈希处理之前在密码中添加第二个盐值(固定的,隐藏的或暴露的,类似于标准盐)来有效地解决,但是,此时,您也可以使用标准熵盐来代替使用用户名的过程。

编辑添加: 很多人都在谈论熵以及盐中的熵是否重要。它是,但并非出于大多数原因,似乎并非如此。

人们普遍认为,熵很重要,因此攻击者很难猜出盐。这是不正确的,实际上是完全不相关的。正如许多人多次指出的那样,受盐影响的攻击只能由具有密码数据库的人进行,而具有密码数据库的人只能查看每个帐户的盐是什么。何时可以平常查找它,是否可猜测都无关紧要。

熵很重要的原因是要避免盐值的聚类。如果盐基于用户名,并且您知道大多数系统都有一个名为“ root”或“ admin”的帐户,则可以为这两种盐创建一个彩虹表,它将破解大多数系统。另一方面,如果使用随机的16位盐,并且随机值具有大致均匀的分布,则您需要一个彩虹表来表示所有2 ^ 16种可能的盐。

这并不是要防止攻击者知道个人帐户的食盐是什么,不是要给他们提供单一盐的大而胖的目标,该目标将在相当大的潜在目标中使用。


同意 我将更多的重点放在用户名的重用上,因为我认为这对使用用户名作为盐的假设系统最有可能成功,而对于使用随机盐的系统则是失败的。
史蒂夫·杰索普

感谢您对跨系统安全性的观点。此外,我猜想将来不会不太可能看到用户特定的彩虹表...
AviD 2009年

@AviD:您是这样认为的吗?那是一个特定的攻击媒介。
大卫·格兰特

2
不是产生盐,不是。唯一受盐影响的攻击是直接针对哈希密码的攻击。除非攻击者拥有您的密码数据库的副本(其中也包含盐),否则攻击无法进行此类攻击。由于攻击者已经拥有了盐,因此它们只需要足够的熵即可避免将任何基本(P)RNG都提供的带有相同盐的多个密码散列。
Dave Sherohman

3
@ acidzombie24:对所有密码使用单个固定盐(在我的经验中通常称为“ nonce”),比对每个密码使用唯一的随机盐安全性较低,因为它仍使攻击者可以轻而易举地确定两个或多个帐户是否共享相同的密码。另一方面,随机数很可能存储在您的代码中,而不是存储在数据库中,因此拥有您的数据库的攻击者将无法访问它。因此,最安全的选择是同时使用系统范围的随机数(存储在代码中)和按密码存储的盐(存储在数据库中)。
戴夫·谢罗曼

29

为了安全地存储密码,绝对需要使用高熵盐。

以我的用户名“ gs”并将其添加到我的密码中,“ MyPassword”为gsMyPassword。使用彩虹表很容易破坏这一点,因为如果用户名没有足够的熵,则可能是该值已存储在彩虹表中,尤其是在用户名较短的情况下。

另一个问题是攻击,您知道用户参与了两个或多个服务。有很多常用的用户名,可能最重要的是admin和root。如果有人创建了一个彩虹表,其中包含带有最常用用户名的盐,则他可以使用它们来破坏帐户。

他们曾经有12位盐。12位是4096种不同的组合。这不够安全,因为如今可以轻松存储大量信息。4096个最常用的用户名也是如此。您的一些用户可能会选择一个属于最常见用户名的用户名。

我找到了这个密码检查器,可以计算出您的密码的熵。密码的熵较小(例如通过使用用户名),使得Rainbowtables尝试覆盖至少所有熵较低的密码,因为它们很可能会出现,因此彩虹表要容易得多。


+1是个好点,但是,您谈论的是潜在的巨大彩虹桌。要掩盖gsMyPassword长度的所有值(假设使用大小写混合的字母数字),表中需要36 ^ 12行!
大卫·格兰特

作为后续:分布式彩虹表项目有63,970个散列哈希,但是36 ^ 12是4,738,381,338,321,616,896!
大卫·格兰特

谢谢,这确实是有道理的-但是正如Mr.PotatoHead指出的那样,您仍在扩展自己的空间,超出了使用RT进行破解的合理可能性。另外,假设我的用户名至少为6-8个字符-熵还能提供什么其他必要的值?
AviD

@土豆:您假设一个彩虹表包含所有可能的字母数字字符组合。不必是这种情况,有效的Rainbow表将包含用于常见密码/哈希的哈希。盐可以防止字典攻击或将rainbabletable / dictionary结合使用。
Guillaume

3
对于具有可预知名称的高特权帐户的系统:在Windows上为“ Administrator”,在* nix上为“ root”,在MSSQL中为“ sa”等,使用用户名作为盐也是一个坏主意
没人

8

确实,由于用户可能会在不同的网站之间共享用户名,因此仅用户名就可能会出现问题。但是,如果用户在每个网站上使用不同的名称,则应该毫无问题。那么,为什么不只是在每个网站上都使其独特。像这样散列密码

哈希函数(“ www.yourpage.com/"+用户名+” /“ +密码)

这应该可以解决问题。我不是密码分析专家,但是我确信我们不使用高熵这一事实会使哈希值变弱。


我相信您是对的,这足够了。但是,由于哈希是一个复杂的数学领域,而且很可能低熵盐会使哈希在将来更容易猜测(尤其是当哈希被破坏时),我不会在安全性上打赌更安全的解决方案并不昂贵。
GeorgSchölly

7

我喜欢同时使用这两种方法:每条记录的高熵随机盐,以及记录本身的唯一ID。

尽管这并没有增加对字典攻击等的安全性,但是它确实消除了附带情况,即有人将自己的盐和哈希值复制到另一条记录,目的是用自己的口令替换口令。

(诚​​然,很难想到这种情况适用的情况,但是在安全方面,我看不出皮带和牙套有什么危害。)


我喜欢将密码绑定到用户的想法。但是,如果攻击者可以更改密码,他当然也可以更改ID。
格奥尔格·舍利

取决于ID是什么:我使用表的主键,您不能真正随意更改它。TBH,如果黑客正在向您的数据库进行写操作,那么您已经遇到了很大的麻烦……
teedyay 2009年

3
不,我喜欢。攻击者通常是“内部人员”。我可以想象这样一个场景:他所追求的不在数据库中,但是如果他可以覆盖数据库中的凭据,那么他可以对自己进行身份验证以执行他想要的操作。
erickson

1
好点子。我们确实发现它使将第一个用户添加到新数据库中变得越来越困难:我们已经有效地使我们的应用程序变得如此安全,以至于我们自己几乎无法破解它们。[此外,请使用特定于应用程序的盐,这样就无法将凭据从一个数据库复制到另一个数据库。]
teedyay 2009年

最后,我发现有人这样说:向用户添加特定于用户的盐。这样可以避免入侵者将某些凭据复制到另一个用户,并且还可以防止黑客在设法访问表中的哈希和盐字段时猜测任何密码。我还想做一件事:不要在哈希中使用大量的迭代。不要走10k或20k,而是类似19835。–
Andrew

3

如果盐是已知的或容易猜测的,则您没有增加词典攻击的难度。甚至有可能创建一个修改后的彩虹表,该表考虑“恒定”盐。

使用独特的盐会增加批量字典攻击的难度。

具有独特的,加密强度高的盐值将是理想的。


2
彩虹表的全部要点是值是预先生成的,并且如果您要为值(例如密码)生成表,再加上给定的常数,那将是一个完全不同的表,您可能还只是直接尝试哈希结果。:)
大卫·格兰特

1
恒定的哈希值一文不值。可以使用一个彩虹表来破解所有密码。盐的目的是不可能创建彩虹表。
格奥尔格·舍利

1
@gs-我不明白为什么您不能构造一个“包含”恒盐效果的彩虹表。攻击空间(密码)不会改变,因此表不必增长,只需​​重新计算即可。
HUAGHAGUAH

@土豆-取决于权衡。如果您公司的2万个登录名都使用相同的恒盐进行哈希处理,则计算一个新的Rainbow表可能要比单独对它们进行字典攻击要便宜。因此,我强调“批量”。
HUAGHAGUAH

3

我想说的是,只要每个密码的盐都不同,您可能就可以了。加盐的要点是,您不能使用标准的Rainbow表来解决数据库中的每个密码。因此,如果您对每个密码使用不同的盐(即使它不是随机的),则攻击者基本上必须为每个密码计算一个新的Rainbow表,因为每个密码使用不同的盐。

使用具有更大熵的盐并没有多大帮助,因为在这种情况下,假定攻击者已经拥有数据库。由于您需要能够重新创建哈希,因此您必须已经知道盐是什么。因此,无论如何,您必须存储盐或组成盐的值。在像Linux这样的系统中,获取盐的方法是已知的,因此拥有秘密盐是没有用的。您必须假设拥有您的哈希值的攻击者可能也知道您的盐值。


3
“问题的关键在于,您不能使用标准的Rainbow表来解决数据库中的每个密码”。我不同意。关键是,您不能使用标准的Rainbow表来解决任何密码。如果盐是用户名,则“根”的彩虹表可能会破解根的pw。
史蒂夫·杰索普

那可能是唯一真正重要的规则。基本上,您希望密码在您的系统上是唯一的,但无论密码是什么都无所谓。不过,它仍然可能很简单。您不需要大量的熵。
Kibbee,

这也是我的想法-但我陷入了“可能还好”的困境。我仍然没有看到这一理论得到证实-或至少证明没有密码分析的含义。
AviD

@onebyone:如果盐由用户名+恒定的本地值组成(我经常使用':'),那么这仍然会破坏标准化的RT,除非它们包含通用的用户名和常见的静态盐值。我怀疑不是这样。
nsayer

和nsayer一起。你可以使用一个全系统的常量字符串,就不会有一个预生成的室温,如#(D83d8,与用户名作为盐一起,这将probalby防止彩虹表攻击。
基比

3

哈希函数的强度不取决于其输入!

使用攻击者已知的盐显然会使构建彩虹表(尤其是对于像root这样的硬编码用户名)更具吸引力,但不会削弱哈希值。使用攻击者不知道的盐将使系统更难以攻击。

用户名和密码的连接可能仍会提供一个智能彩虹表的条目,因此,使用一系列带有哈希值密码的伪随机字符的盐存储起来,可能是一个更好的主意。举例说明,如果我有用户名“ potato”和密码“ beer”,则哈希的串联输入为“ potatobeer”,这是彩虹表的合理输入。

每次用户更改密码时更改盐值可能会有助于克服长时间的攻击,以及实施合理的密码策略(例如混合大小写,标点符号,最小长度,n周后更改)会有所帮助。

但是,我想说您选择摘要算法更为重要。例如,对于生成彩虹表的人来说,使用SHA-512比MD5会更痛苦。


该功能的强度没有改变,但是输出肯定会改变。如果输入可以受到影响或已知,那么也许可以推断出哈希值。那是风险。
马丁·卡彭特

@Martin:如果您是否有匹配项,您唯一应该能够从哈希值中推断出来!将“ roota”或“ rootb”(其中“ a”和“ b”代表密码)放入哈希函数将为您提供截然不同的输出。
大卫·格兰特

攻击者使用彩虹表知道了这些盐。
格奥尔格·舍利

服务器必须知道未加密的盐(以便对照哈希检查密码),因此可以认为攻击者可以访问该盐,或者可以很容易地获得它。
乔治·Schölly

对,对,这就是给定的-更具体地说,我的意思是整体密码系统(或-子系统,wrt哈希)的强度。
AviD

1

Salt应该具有尽可能大的熵,以确保应该多次对给定的输入值进行哈希处理,结果哈希值将尽可能接近始终保持不同。

在盐中使用尽可能多的熵来使用不断变化的盐值将确保散列的可能性(例如,密码+盐)将产生完全不同的散列值。

盐的熵越小,生成相同的盐值的机会就越大,因此生成相同的哈希值的机会就越多。

当输入已知时,散列值是“常数”的本质是“字典”或“彩虹”表如此有效的“常数”。通过尽可能多地改变所得哈希值(通过使用高熵盐值)可确保对相同的输入+随机盐进行哈希处理将产生许多不同的哈希值结果,从而击败(或至少大大降低了)彩虹表攻击。


同样,我并不是在指使用单一的常量盐,而是非随机的,而是用户唯一的值。例如userId。
AviD

重点是您的食盐值永远不应恒定。散列的每件事,无论是否具有相同的“输入”值,都应具有不同的盐。Dave Sherohman解释了使用均匀的用户唯一值的缺点,这些值在每次哈希计算中基本上保持不变。
CraigTP

-1

熵是Salt值的点。

如果盐后面有一些简单且可重现的“数学”,则与盐不存在一样。只需添加时间值就可以了。


我不明白这个评论。您说“使用熵”,然后:“使用时间” ??
马丁·卡彭特

如果用户名用于加盐,则说明熵不够。但是,如果您使用用户名+当前日期-是这样,因为很难猜测何时精确创建了盐。
dmajkic,2009年

“足够熵”是主观的;这是您的标准。将此值基于时间可能不够。
马丁·卡彭特

没有“绝对真实随机性”这样的东西。我们要说何时“足够好”。如果您认为在这种情况下时间不够用,请使用其他方法。 stackoverflow.com/questions/84556/...
dmajkic

实际上,重点是要使每个哈希结果都是唯一的-以防止(a)彩虹表攻击和(b)相同的密码标识。问题是,如果需要的话,熵还需要什么呢?
AviD 2009年
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.