盐生成和开源软件

据我所知,生成盐的最佳实践是使用存储在源代码中的一些神秘公式(甚至魔法常数)。

我正在做一个项目,我们计划以开源的形式发布,但问题是,随着源代码而来的是生成盐的秘密公式,因此能够在我们的网站上运行彩虹桌攻击。

我认为很多人在我之前就考虑过这个问题,我想知道什么是最佳实践。在我看来,如果代码是开源的,那么使用 salt 是毫无意义的,因为 salt 可以很容易地进行逆向工程。

有什么想法吗?

26754 次浏览

真正的盐只是需要为每个条目的独特性。即使攻击者可以计算出盐是什么,它也会使彩虹表极难创建。这是因为 salt 在被散列之前被添加到密码中,所以它实际上增加了虹表必须包含的所有条目的总数,以便拥有密码字段的所有可能值的列表。

由于有关腌制散列的问题经常出现,而且似乎对这个主题有些困惑,所以我扩展了这个答案。


盐是什么?

Salt 是一组固定长度的 随机的字节,它被添加到哈希算法的输入中。


为什么给散列加盐(或播种)很有用?

向散列中添加一个随机的 salt 可以确保相同的密码将产生许多不同的散列。Salt 通常与 hash 函数的结果一起存储在数据库中。 给散列加盐有以下几个好处:

  1. 加盐极大地增加了预计算攻击(包括 彩虹桌)的难度/成本
  2. Salting 确保相同的密码不会导致相同的散列。 这将确保您无法确定两个用户是否具有相同的密码。而且,更重要的是,您无法确定同一个人是否在不同的系统中使用相同的密码。
  3. Salting 增加了密码的复杂性,从而极大地降低了两者的有效性(只有当} 与 hash 分开存储时才会出现这种情况)。
  4. 适当的适应性 非常喜欢增加了预计算攻击的存储需求,直到它们不再实用。(8个字符大小写敏感的字母数字密码,加16位元,散列为128位元,将占用 差不多200个 艾字节而不会减少彩虹)。


没必要把盐藏起来。

Salt 不是密钥,而是通过使散列函数特定于每个实例来“工作”。对于带盐的散列,不存在 散列函数,而是每个可能的 salt 值都有一个函数。这样可以防止攻击者以低于攻击一个密码成本 N倍的价格攻击 N散列密码。这就是盐的重点。
“ secret salt”不是 salt,它被称为“ key”,这意味着您不再计算 hash,而是计算 讯息鑑别码(MAC)。计算 MAC 是一件棘手的事情(比简单地将一个键和一个值组合到一个散列函数中要棘手得多) ,而且它是一个完全不同的主题。

在每个实例中使用 salt 肯定是随机的。这确保攻击者必须分别攻击每个加盐的散列。
如果您依赖于您的}(或者}算法)是保密的,那么您就进入了 隐晦式安全的领域(不会工作)。最有可能的是,您并没有从盐的保密性中获得额外的安全性; 您只是获得了温暖而模糊的安全感。所以它不仅没有让你的系统更加安全,反而让你从现实中分心。


那么,为什么盐必须是随机的呢?

从技术上讲,盐应该是 独一无二。Salt 的要点是区分每个散列密码。这意味着 全世界。由于没有按需分配独特盐类的中央机构,我们只能依靠次好的方法,即使用不可预测的随机发生器进行随机选择,最好是在一个足够大的盐空间内,使碰撞不太可能发生(两个实例使用相同的盐值)。

试图从某些“可能是唯一的”数据(例如用户 ID)中获取一些信息是很有诱惑力的,但这种方案往往会因为一些令人讨厌的细节而失败:

  1. 如果您使用 例如,用户 ID,一些攻击不同系统的坏人可能会共享他们的资源,并为用户 ID 1到50创建预先计算好的表。用户 ID 是唯一的 全系统,但不是 全世界

  2. 这同样适用于 用户名: 每个 Unix 系统有一个“根”,但是世界上有许多根。为“ root”创建一个彩虹表是值得的,因为它可以应用于数百万个系统。更糟糕的是,还有很多“ bob”,很多人没有受过系统管理员培训: 他们的密码可能非常弱。

  3. 唯一性也是暂时的。有时,用户会更改密码。对于每个 新密码,必须选择一个 新盐。否则,攻击者获得旧密码的 hash 和新密码的 hash 可能会尝试同时攻击这两个密码。

使用从加密安全的、不可预测的 PRNG 中获得的随机盐可能是某种过度杀伤,但至少它 可以证明保护您免受所有这些危险。这不是为了防止攻击者知道什么是 个人盐,而是为了不给他们一个大而肥的目标,这个目标将被用于大量的潜在目标。随机选择使得目标尽可能薄。


总而言之:

使用随机的,均匀分布的,高熵盐。在创建新密码或更改密码时使用新 salt。将 salt 与散列密码一起存储。支持大盐(至少10个字节,最好是16个或更多)。

Salt 不会将错误的密码变成好的密码。它只是确保攻击者至少会为他破解的 abc0错误密码支付字典式攻击。


有用资料来源:
Stackoverflow.com : < em > 密码哈希的非随机盐
布鲁斯 · 施奈尔: 实用密码学 (书)
Matasano 安保: < em > 不要再玩彩虹桌了
Unix crypt 从1976年起就开始使用盐
Owasp.org : < a href = “ http://www.owasp.org/index.php/Hash _ Java # Why _ add _ salt _.3F”rel = “ noReferrer”> < em > Why add salt
Openwall.com :

免责声明:
我不是安全专家
如果有任何安全专家在那里发现错误,请做评论或编辑这个维基答案。

您只需在运行时为每条记录生成一个随机的 salt。例如,假设您正在数据库中存储散列用户密码。您可以在运行时生成一个由8个字符组成的随机字符串,该字符串由大小写字母数字字符组成,将其预置到密码散列 那个字符串中,并将其存储在数据库中。由于有628可能的盐,生成彩虹表(对于每个可能的盐)将是非常昂贵的; 而且由于你对每个密码记录使用一个独特的盐,即使攻击者已经生成了一对匹配的彩虹表,他仍然无法破解 每个密码。

你可以根据你的安全需要改变你的 salt 生成的参数,例如,你可以使用一个更长的 salt,或者你可以生成一个随机字符串,它也包含句读,来增加可能的 salt 数量。

使用一个随机函数生成器生成 salt,并将其存储在数据库中,将 salt 设置为每行一个,然后将其存储在数据库中。

我喜欢在 django 注册中如何生成 salt

salt = sha_constructor(str(random.random())).hexdigest()[:5]
activation_key = sha_constructor(salt+user.username).hexdigest()
return self.create(user=user,
activation_key=activation_key)

他使用随机数生成的 sha 和用户名的组合来生成散列。

Sha本身是众所周知的强大和牢不可破。添加多个维度以生成 salt 本身,其中包含随机数 sha 和用户特定的组件 你的安全系统牢不可破!

自从 Unix 变得流行起来,存储密码的正确方法就是添加一个随机值(salt)并散列它。把盐留在你以后可以拿到的地方,但是你希望坏人不会拿到的地方。

这有一些好的效果。首先,坏人不能仅仅列出一个预期的密码列表,比如“ Password1”,将它们散列到一个彩虹表中,然后通过你的密码文件寻找匹配。如果你有一个很好的两字节的 salt,他们必须为每个预期的密码生成65,536个值,这使得彩虹表不太实用。其次,如果您能够防止坏人查看您的密码文件,那么计算可能的值就会变得更加困难。第三,你让坏人无法确定一个人是否在不同的网站上使用相同的密码。

为此,您需要生成一个随机的 salt。这应该生成所需范围内的每个数字具有一致的概率。这并不难; 一个简单的线性同余随机数生成器就可以很好地实现。

如果你有复杂的计算来制作盐,那你就做错了。如果你是根据密码来计算的,那你就大错特错了。在这种情况下,您所做的只是使散列变得复杂,而没有在功能上添加任何 salt。

没有一个擅长安全的人会依赖于隐藏算法。现代密码学是基于已经被广泛测试的算法,为了被广泛测试,它们必须是众所周知的。一般来说,人们发现使用标准算法比滚动自己的算法更安全,并希望它是好的。代码是否开源并不重要,坏人仍然可以分析程序的功能。

对于加密数据并将其发送到远程服务器的桌面应用程序,如何考虑每次使用不同的 salt?

使用带有用户密码的 PKCS # 5,它需要一个 salt 来生成一个加密密钥,以便对数据进行加密。我知道在桌面应用程序中保持 salt 硬编码(混淆)不是一个好主意。

如果远程服务器必须永远不知道用户的密码,是否可能每次使用不同的 salt?如果用户在另一台计算机上使用桌面应用程序,如果他没有密钥(在软件中没有硬编码) ,它将如何能够解密远程服务器上的数据?