关于安全性:密码哈希的非随机盐

Non-random salt for password hashes

更新:我最近从这个问题中了解到,在下面的整个讨论中,我(我确信其他人也这么做了)有点困惑:我一直称之为彩虹表的,实际上是一个哈希表。彩虹表是更复杂的生物,实际上是地狱人散列链的变体。虽然我相信答案仍然是一样的(因为它不归结于密码分析),但有些讨论可能有点偏颇。问题:"彩虹桌是什么?它们是如何使用的?"

通常,我总是建议使用加密的强随机值作为salt,用于哈希函数(例如用于密码),例如防止彩虹表攻击。

但是,盐在密码学上是随机的吗?在这方面,任何唯一值(每个用户唯一,例如userid)是否足够?它实际上可以防止使用一个彩虹表破解系统中的所有(或大多数)密码…但是,缺乏熵真的削弱了哈希函数的加密强度吗?

注意,我不会问为什么要使用salt,如何保护它(不需要),使用一个常量散列(不需要),或者使用什么类型的散列函数。盐是否需要熵。

感谢所有的答案,但我想集中在我(一点)不太熟悉的领域。主要是对密码分析的影响-如果有人从密码数学POV输入信息,我会非常感激。此外,如果还有其他未考虑的向量,那么这也是很好的输入(请参见多个系统上的@dave sherohman point)。除此之外,如果你有任何理论、想法或最佳实践-请用证据、攻击场景或经验证据来支持这一点。甚至是对可接受的权衡的有效考虑…我熟悉这个主题的最佳实践(Capital B Capital P),我想证明这实际上提供了什么价值。

编辑:这里有一些很好的答案,但我认为正如@dave所说,它可以归结为彩虹表中的常用用户名…还有可能不太常见的名字。但是,如果我的用户名是全局唯一的呢?对于我的系统不一定是唯一的,但针对每个用户-例如电子邮件地址。没有为单个用户构建RT的动机(正如@dave强调的那样,salt不是保密的),这仍然会阻止集群。唯一的问题是,我可能在不同的网站上有相同的电子邮件和密码,但是Salt无论如何也不能阻止。那么,归根结底就是密码分析——熵是否必要?(我目前的想法是,从密码分析的角度来看,这是不必要的,但从其他实际的原因来看。)


salt传统上存储为哈希密码的前缀。这使得任何访问密码散列的攻击者都知道它。将用户名用作salt或不影响该知识,因此它不会影响单个系统的安全性。

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

这种想法带来的更大的危险是,用户名通常会被重复使用——例如,几乎任何你想访问的站点都会有一个名为"dave"的用户帐户,"admin"或"root"甚至更为常见——这将使构建针对具有这些常用名称的用户的彩虹表变得更加容易和有效。

这两个缺陷都可以通过在散列密码之前向密码中添加第二个salt值(固定的和隐藏的或像标准salt一样暴露的)来有效地解决,但是在这一点上,您也可以使用标准的entropic salt,而不是在其中使用用户名。

编辑补充:很多人都在谈论熵和盐的熵是否重要。的确如此,但这并不是因为大多数评论都在思考的原因。

一般认为熵很重要,所以攻击者很难猜测盐的存在。这是不正确的,事实上,完全不相关。正如许多人所指出的那样,只有拥有密码数据库的人才能进行受salt影响的攻击,拥有密码数据库的人才能查看每个帐户的salt是什么。你什么时候可以细细地查一下,这是否是可以猜测的无关紧要。

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

这不是为了阻止攻击者知道单个帐户的salt是什么,而是为了不给他们一个单独salt的大而胖的目标,这个目标将被用于潜在目标的很大一部分。


使用高熵盐绝对是安全存储密码的必要条件。

把我的用户名"gs"加在我的密码"my password"上,得到gsmypassword。使用彩虹表很容易打破这一点,因为如果用户名没有足够的熵,那么这个值可能已经存储在彩虹表中,特别是如果用户名很短。

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

他们以前有12块盐。12位是4096种不同的组合。这还不够安全,因为现在可以轻松地存储大量信息。这同样适用于4096个最常用的用户名。您的一些用户可能会选择属于最常见用户名的用户名。

我找到了这个密码检查程序,它计算出你密码的熵。密码中的熵更小(比如使用用户名),使得彩虹表更容易使用,因为它们试图用低熵覆盖至少所有的密码,因为它们更容易发生。


的确,用户名本身可能有问题,因为人们可以在不同的网站上共享用户名。但是,如果用户在每个网站上有不同的名称,这应该是相当没有问题的。所以为什么不在每个网站上让它独一无二呢?像这样散列密码

hashfunction("www.yourpage.com/"+用户名+"/"+密码)

这样可以解决问题。我不是密码分析大师,但我肯定怀疑我们不使用高熵这一事实会使散列变得更弱。


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

虽然这并不能增加字典攻击等的安全性,但它确实消除了一些边缘情况,即有人将其salt和hash复制到另一个记录,目的是用自己的密码替换密码。

(诚然,很难想到这样的情况,但在安全问题上,我看不到安全带和背带有任何危害。)


我会说,只要每个密码的盐是不同的,你可能会没事的。盐的要点是,不能使用标准的彩虹表来解决数据库中的每个密码。因此,如果对每个密码应用不同的salt(即使它不是随机的),攻击者基本上必须为每个密码计算一个新的彩虹表,因为每个密码使用不同的salt。

使用具有更多熵的salt并没有什么帮助,因为在本例中,假定攻击者已经拥有数据库。因为您需要能够重新创建哈希,所以您必须已经知道盐是什么。所以您必须将盐或组成盐的值存储在文件中。在Linux这样的系统中,获取salt的方法是已知的,因此没有使用秘密salt。您必须假设拥有散列值的攻击者也可能知道您的salt值。


如果盐是已知的或很容易猜测的,则不会增加字典攻击的难度。甚至可以创建一个考虑到"恒定"盐的改进彩虹表。

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

拥有独特的密码强盐值是理想的。


哈希函数的强度不是由其输入决定的!

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

用户名和密码的串联可能仍然为智能彩虹表提供一个条目,因此使用一系列伪随机字符的salt(与哈希密码一起存储)可能是一个更好的主意。举例来说,如果我有用户名"potato"和密码"beer",那么哈希的连接输入是"potatobeer",这是彩虹表的合理输入。

每次用户更改密码时更改salt可能有助于抵御长时间的攻击,同样,执行合理的密码策略也会有所帮助,例如大小写混合、标点符号、最小长度、n周后更改。

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


salt应该具有尽可能多的熵,以确保如果给定的输入值被多次散列,那么得到的散列值将尽可能接近,总是不同的。

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

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

当输入已知时,散列值是"常量"的性质,"常量"允许字典攻击或彩虹表如此有效。通过尽可能改变产生的散列值(使用高熵的盐值),确保散列相同的输入+随机盐将产生许多不同的散列值结果,从而击败(或至少大大降低)彩虹表攻击的效果。


熵是盐值的点。

如果盐后面有一些简单和可复制的"数学",那就和盐不存在时一样。只需增加时间值就可以了。