25

我的理解是,盐并不是要保密的,它只是为了与任何集中式标准不同,因此您不能开发彩虹表或类似的攻击来破坏使用该算法的所有哈希,因为盐会破坏彩虹桌。我在这里的理解可能并不完全正确,如果我错了,请纠正我。

在一个广泛使用的开源软件中,salt 将广为人知,这使您容易受到攻击,因为现在他们可以简单地攻击您的 hash 的 salted 版本并创建包含 salt 数据的彩虹表。

在我看来,有两种选择可以解决这个问题。首先是在每个新版本的软件中更改盐,但这并不好,因为新版本的软件将不再能够针对旧密码哈希进行测试。

我想到的第二个解决方案是为每个密码存储一个盐;换句话说,每个密码都有不同的盐。缺点是盐必须以某种方式与密码哈希相关联,可能只是将它们粘贴在数据库中的密码旁边。甚至可以使用用户名(但可能不会,用户名可能太短)。

我的问题是,这可以接受吗?将盐直接与其散列的密码一起存储是否有任何额外的风险?在我看来,将盐存储在源代码中没有什么不同,因此将盐与密码一起存储不会造成安全损失。

免责声明:我没有将它用于任何现实生活中的安全系统。事实上,我从未设计过任何类型的密码系统。我只是让自己对安全问题进行了模糊的教育。

4

7 回答 7

20

更新:使用合适的库,例如Python 的passlib

这些负责生成每个密码的盐,并使用适当的散列算法(仅使用诸如 SHA1 之类的加密散列是不够的;您必须以一种使其反转非常慢的方式应用它,例如循环 1000 或更多次等等。这就是密码散列函数(如bcrypt )的工作方式。密码存储库可以正确完成所有这些操作;它们通常会生成一个带分隔符的字符串,以便它们可以确定所使用的散列系统和工作因子;您只需存储字符串而无需需要知道这一点。


您可以将盐以“纯文本”形式存储在表中。

  • 盐不需要保密才能有效

  • 它只需要是随机的。

盐通过使散列值与相同或其他数据库中的相同密码无法比较来增强密码,并使散列查找(例如“彩虹表”)的公共密码的大型预生成列表无效。

因此,每个用户的盐是唯一的,并且是与密码一起存储的一些随机值,这一点至关重要;问题中概述的替代方案(使用用户名作为盐,对整个应用程序使用单个盐值)每个都失败:

  • 如果系统使用用户名或其他琐事,则可以将密码与其他系统中具有相同名称的其他用户进行比较(想象一下“管理员”或“root”用户帐户在不同系统中使用相同密码的频率.. .)

  • 如果系统对同一系统中的所有用户使用单个随机盐,那么偶然拥有相同密码的两个用户将具有相同的哈希值,并且猜测一个用户的密码会轻易危及另一个用户的密码。

于 2009-10-30T08:00:45.750 回答
10

试图保守盐的秘密是没有意义的的,因为盐和散列密码的整个实践之所以存在,只是因为我们从经验中知道,我们甚至不能完全可靠地保密我们的数据库。您最多可以单独存储盐,并希望访问您的数据库的攻击者找不到它,但是如果您使用了良好的散列算法和足够长的单个盐,那么无论哪种方式您都应该是安全的。

加盐的目的仅仅是为了确保您无法在整个数据库甚至多个数据库上分摊暴力攻击的成本。

首先是在每个新版本的软件中更改盐,但这并不好,因为新版本的软件将不再能够针对旧密码哈希进行测试。

我见过的一种变体是在安装过程中生成一个随机盐(当然,跨版本保持这个),以便每个正在运行的实例都有一个不同的实例。当然,为每个密码使用不同的盐(也许除了上述之外)更好。

于 2009-10-30T08:02:06.847 回答
1

根据定义, salt必须是随机的才能有效。不要为此使用任何确定性值。这当然意味着您需要将其与散列密码一起存储在数据库中。传统上, UNIX 系统甚至将散列存储在与密码相同的字段中(盐是密码的固定长度前缀)。在数据库中,您可以在 users 表中添加额外的列。

于 2009-10-30T07:51:30.410 回答
0

为每个密码生成唯一的盐是完全正常的。盐可能是现有材料的产物(例如 UserID 等)或随机生成的。优点是随着盐强度的增加,对加密信息的攻击变得更加不切实际。

记住:每个加密算法都是易破解的。只有当破解保护(通过彩虹表或其他方式)的成本高于信息的价值时,信息才可能被认为是“安全的”。

编辑:

假设您对密码学非常陌生,这里还有一些提示:

  • 长盐比短盐好。
  • 盐的可能值越多越好。字母数字盐比数字盐好。二元盐优于字母数字盐。
  • 不会降低针对单个密码的蛮力攻击的可能性。
于 2009-10-30T07:54:22.417 回答
0

您的第二种解决方案“每个密码存储一个盐”是正确的并且通常使用。

“Salt”主要是为了难以检测两个用户何时拥有相同的密码 - 因此您将已知的“Salt”混合到密码中。需要在密码检查时获取盐。

因此,通常要么生成随机盐并将其与密码一起存储,要么使用其他标识符(用户 ID、用户名等)作为盐。

于 2009-10-30T08:01:56.880 回答
0

对数据库中的所有密码使用单一的盐是有帮助的,但比给每个用户一个唯一的盐安全性要低得多。

基本上:更长的(以字节为单位)密码+盐增加了搜索空间,因此更难使用“股票标准”彩虹表。

但是,如果所有条目都使用相同的盐,那么就有可能专门创建一个彩虹表来攻击您的软件。如果您的用户群很大,那么有人可能会决定制作这样的彩虹表。

例如,如果您在散列之前在每个密码的末尾添加“and a lot of salt”,攻击者可以构建一个由大量字符串生成的散列值表,所有这些字符串都以“and a lot of salt”结尾.

出于这个原因,每个用户的盐是最好的方法。但是,请记住,您还希望密码+盐为“长”。

如果您想使用主键,最好采用主键的哈希值而不是使用主键本身,因为如果用户 43 的密码+盐看起来像“myPassword00000000043”,那么攻击者可以构建一个假设中间有很多零的表格。不过,创建时间戳和随机字符串可能是更好的选择,因为 PKey 有时很容易找到或猜到。

注意:我不是真正的加密专家,请勿在真实系统中使用此建议。

于 2009-10-30T08:09:27.543 回答
-1

您实际上已经在用户表中存储了一个盐值:表的 pkey。

你不必发明一个新的柱子来储存盐。只需使用 pkey。这个想法当然假定您确实有一个与用户名关联的 pkey。例如,用户名不是表中的 pkey。

这是一个近乎重复的 wtb:密码散列、盐和散列值的存储

于 2009-10-30T07:32:51.150 回答