关于安全:把salt 藏起来做hash的必要性

The necessity of hiding the salt for a hash

在工作中,我们对盐有两种相互竞争的理论。我工作的产品使用用户名或电话号码之类的东西来调味。本质上,每个用户都有不同的功能,但我们可以随时使用。另一个产品为每个用户随机生成一个salt,并在每次用户更改密码时进行更改。然后在数据库中对salt进行加密。

我的问题是,第二种方法是否真的有必要?我可以从纯理论的角度理解,它比第一种方法更安全,但是从实用性的角度来看呢?现在要对用户进行身份验证,salt必须未加密并应用于登录信息。

经过思考,我只是没有看到这种方法真正的安全收益。将salt从一个帐户更改为另一个帐户,仍然会使某些人难以尝试强制执行哈希算法,即使攻击者知道如何快速确定每个帐户的内容。这是基于密码足够强的假设。(显然,找到一组密码的正确散列值(它们都是两位数字)要比找到正确的8位密码散列值容易得多)。我的逻辑是错误的,还是我遗漏了什么?

编辑:好吧,这就是为什么我认为对盐进行加密是非常不明智的。(让我知道我是否在正确的轨道上)。

对于下面的解释,我们假设密码总是8个字符,salt是5个字符,并且所有密码都由小写字母组成(这只是使数学更简单)。

每个条目都有不同的盐意味着我不能使用相同的彩虹表(实际上,如果我有一个足够大的彩虹表,从技术上讲我可以,但现在我们忽略它)。从我的理解来看,这是盐的真正关键,因为要破解每一个账户,我必须重新发明轮子,以便为每一个账户说话。现在,如果我知道如何将正确的salt应用于密码以生成哈希,我会这样做,因为salt实际上只是扩展了哈希短语的长度/复杂性。所以我会减少可能的组合的数量,我需要生成"知道"我有密码+盐从13^26到8^26,因为我知道盐是什么。现在这样做容易了,但仍然很难。

所以要加密盐。如果我知道salt是加密的,我不会首先尝试解密(假设我知道它有足够的加密级别)。我会忽略它。回到上一个例子,我将生成一个更大的彩虹表,其中包含13^26的所有键,而不是试图弄清楚如何解密它。不知道盐会让我慢下来,但我不认为它会增加一项艰巨的任务,那就是先破解盐加密。这就是为什么我认为它不值得。思想?

下面是一个链接,描述了在暴力攻击下密码可以保存多长时间:http://www.lockdown.co.uk/?科比


不必藏盐。

每种土豆泥都应使用不同的盐。实际上,从加密质量的随机数生成器中获取8个或更多的字节很容易实现这一点。

从我以前的回答来看:

Salt helps to thwart pre-computed dictionary attacks.

Suppose an attacker has a list of likely passwords. He can hash each
and compare it to the hash of his victim's password, and see if it
matches. If the list is large, this could take a long time. He doesn't
want spend that much time on his next target, so he records the result
in a"dictionary" where a hash points to its corresponding input. If
the list of passwords is very, very long, he can use techniques like a
Rainbow Table to save some space.

However, suppose his next target salted their password. Even if the
attacker knows what the salt is, his precomputed table is
worthless—the salt changes the hash resulting from each password. He
has to re-hash all of the passwords in his list, affixing the target's
salt to the input. Every different salt requires a different
dictionary, and if enough salts are used, the attacker won't have room
to store dictionaries for them all. Trading space to save time is no
longer an option; the attacker must fall back to hashing each password
in his list for each target he wants to attack.

So, it's not necessary to keep the salt secret. Ensuring that the
attacker doesn't have a pre-computed dictionary corresponding to that
particular salt is sufficient.

再想一想,我意识到欺骗自己,让自己以为盐可以被藏起来是危险的。最好假设盐不能被隐藏,尽管如此,设计系统还是安全的。我在另一个答案中提供了更详细的解释。


这里的答案是问你自己你真正想要保护什么?如果有人可以访问您的数据库,那么他们就可以访问加密的salt,而且他们可能也可以访问您的代码。他们能用这些方法解密加密的盐吗?如果是这样的话,那么加密无论如何都是无用的。salt确实是用来制作它的,所以如果它被破坏了,就不可能形成一个彩虹表来一次性破解整个密码数据库。从这个角度来看,只要每个salt都是唯一的,没有区别,就需要对每个密码分别使用您的salt或加密salt进行暴力攻击。


隐藏的盐不再是盐。是胡椒。它有它的用途。它不同于盐。

Pepper是一个添加到密码+salt中的密钥,它使哈希成为一个HMAC(基于哈希的消息身份验证代码)。访问哈希输出和salt的黑客理论上可以强行猜测将生成哈希的输入(从而在密码文本框中通过验证)。通过添加Pepper,您可以以加密随机方式增加问题空间,从而使问题变得难以处理,而无需使用严重的硬件。

有关胡椒粉的更多信息,请查看此处。

也见HMAC。


第二种方法只是稍微安全一点。盐可以保护用户免受字典攻击和彩虹表攻击。它们使野心勃勃的攻击者更难破坏您的整个系统,但仍然容易受到集中在系统某个用户身上的攻击。如果你使用公开的信息,比如电话号码,而攻击者意识到了这一点,那么你就为他们的攻击节省了一步。当然,如果攻击者获取了整个数据库、salts和所有内容,问题就没有了。

编辑:在重新阅读了这个答案和一些评论之后,我发现有些困惑可能是因为我只比较了问题中提出的两个非常具体的案例:随机盐与非随机盐。如果攻击者得到了整个数据库,那么使用电话号码作为salt的问题是没有意义的,而完全不是使用salt的问题。


我对"盐"的理解是它使破解变得更困难,但它不会试图隐藏额外的数据。如果您试图通过将salt设置为"秘密"来获得更高的安全性,那么您只需要在加密密钥中有更多的比特。


... something like a user name or phone number to salt the hash. ...

My question is if the second approach is really necessary? I can understand from a purely theoretical perspective that it is more secure than the first approach, but what about from a practicality point of view?

从实际的角度来看,salt是一个实现细节。如果您更改了收集或维护用户信息的方式,并且用户名和电话号码有时都会更改,那么为了使用确切的示例,您可能已经破坏了安全性。您是否希望这样一个面向外部的变化有更深层次的安全问题?

停止要求每个帐户都有一个电话号码的要求是否需要进行完整的安全审查,以确保您没有打开这些帐户进行安全折衷?


下面是一个简单的例子,说明为什么每个哈希都有相同的盐是不好的。

考虑下表

1
2
3
UserId  UserName,   Password
     1  Fred       Hash1 =  Sha(Salt1+Password1)    
     2  Ted        Hash2 =  Sha(Salt2+Password2)

情况1,当盐1与盐2相同时如果hash2替换为hash1,则用户2可以使用用户1密码登录。

案例2当盐1不是同一盐2如果hash2替换为hash1,则用户2不能使用用户1密码登录。


有两种方法,目标不同:

  • "salt"用于使两个相同的密码以不同的方式加密。这样,入侵者就不能有效地使用字典攻击来攻击整个加密密码列表。

  • (共享的)"秘密"是在散列消息之前添加的,这样入侵者就不能创建自己的消息并接受它们。


我想把盐藏起来。我使用10位salt,在散列密码之前,将一个从1到1024的随机数前置到密码的开头。当比较用户输入的密码和散列值时,我从1循环到1024,并尝试所有可能的salt值,直到找到匹配的值。这需要不到1/10秒的时间。我从php密码哈希和密码验证中得到了这样的想法。在我的例子中,10比特盐的成本是10。或者根据其他用户的说法,隐藏的"盐"被称为"胡椒"。salt未在数据库中加密。这是野蛮的强迫。这将使彩虹表需要将哈希值反转1000倍。我使用sha256是因为它很快,但仍然被认为是安全的。


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

每个密码的唯一salt的目的是防止字典攻击整个密码数据库。

对每个密码加密唯一的salt会使破解单个密码变得更加困难,是的,但是您必须权衡是否真的有很多好处。如果攻击者通过暴力手段发现该字符串:

1
Marianne2ae85fb5d

散列到存储在数据库中的散列,真的很难弄清楚哪个部分是过程,哪个部分是盐?