你们认为使用密码的前 8 位本身对密码进行加盐与使用存储的盐对密码进行哈希处理具有相同的结果吗?
[澄清]我不是存储盐,而是在身份验证期间从密码本身创建。
后续问题,而不是使用前 8 位如何作为盐的第一个(密码 mod(素数)的长度)?这不是比普通密码散列更安全吗?
你们认为使用密码的前 8 位本身对密码进行加盐与使用存储的盐对密码进行哈希处理具有相同的结果吗?
[澄清]我不是存储盐,而是在身份验证期间从密码本身创建。
后续问题,而不是使用前 8 位如何作为盐的第一个(密码 mod(素数)的长度)?这不是比普通密码散列更安全吗?
这个方案看起来很聪明,但事实并非如此。
盐通常以明文形式存储。它们有一个目的——限制预先计算的哈希表的可用性。还有一个副作用是,为具有相同密码的两个不同用户帐户计算的两个哈希值不会相同。
通过将密码的一部分存储为盐,您正在降低应用程序的安全状态,并使事情复杂化。以下几点假设盐的储存:
盐的密码学性质
这是基于保罗的回答和散布在此页面上的评论。本节不假设盐的储存,而是关于如何选择盐的说明。任何用作密码盐的数据都必须满足某些加密属性。最重要的是
盐在系统中存储的密码中必须是唯一的。
如果盐不是唯一的,那么人们将失去为系统管理的每个密码创建唯一哈希的能力,从而导致哈希转储可能会泄露跨帐户使用的密码或字典中存在的密码。
不能保证所讨论的方案具有此属性。事实上,很容易假设该属性在超过 2^8 = 256 个用户的系统中必然不存在,从而使该方案毫无用处。
此外,如果有人认为该方案可以合理地防止预先计算的哈希,那么该假设是没有实际意义的。它假设攻击者没有可支配的资源来计算哈希以在合理的时间范围内破坏所有帐户。使用具有唯一性的加密属性的盐肯定会大大降低攻击者的速度,因为计算出的散列仅对一种盐有效,而对其他盐无效(即必须重新计算字典中任何密码的散列对于每个用户)。如果要采用当前方案,攻击者可以限制自己只计算字典中每个密码的 1 个哈希,这与不使用盐没有什么不同,因此一开始就没有盐。
这将导致加密盐的另一个属性:
盐必须增强系统对蛮力攻击等的抵抗力。
通过使用从密码派生的盐,一个人失去了这个属性,因为字典中每个密码的哈希可以在或多或少相同的时间内计算出来,无论有没有盐。
为此,大多数系统被设计为使用安全的 PRNG 生成足够长度的盐。其中一条评论指出,使用“服务名”+“用户名”组合就足够了。我会说这是一件好事。服务名称通常充当辣椒(尤其是在未存储时),因此无法使用相同的散列方案在服务之间复制和使用散列本身。用户名足以用作盐,除非用户名是公开的(root
*nix 中的帐户,或Administrator
例如,在 Windows 中)。如果您的用户名将在多个部署中公开且一致,那么使用 n 位随机性应该是要走的路。这是第二个属性的扩展,因为任何盐的选择都必须考虑对所有部署的暴力攻击的抵抗力。
后续问题指出 -
不是使用前 8 位,如何将第一个(密码 mod(素数)的长度)位作为盐?这不是比普通密码散列更安全吗?
不,不保证盐在用户帐户中是唯一的。(见第一个密码学性质)。
使用部分密码作为盐并不比完全不使用盐好——它只是稍微重新定义了你的散列函数。
salt 的全部意义在于对密码散列进行一些输入,而与密码本身无关,试图进行字典攻击的对手无法提前预测。 n位盐迫使他在他的字典中为每个密码创建 2^ n 个哈希,每个可能的盐值一个。在他窃取密码文件之前,他不知道实际使用了哪些盐值。
但是,如果盐只是密码的某个函数,那么攻击者确切地知道盐的值将用于任何特定的密码,所以他只需要在他的字典中的每个密码一个哈希值,与存在的情况相同一点盐都没有,他可以提前建好这本词典。
另一种看待它的方式:加盐可防止碰巧具有相同密码的两个帐户具有相同的密码哈希值。(嗯,有 2^- n的机会为每个人随机选择相同的盐,但你知道我的意思。)如果盐是根据密码本身计算而不是随机生成的,那么具有相同密码的两个帐户将始终具有相同的密码哈希。