将用户的输入用作 SALT 是个好主意吗?

信息安全 密码 哈希
2021-09-06 02:33:54

我在这里阅读了许多关于密码散列和加盐的 IT 安全问答。

我正在为我们的社区网站构建一个简单的注册表单,我们的成员将使用它来创建他们的帐户。我正在认真讨论向用户询问需要一个单词答案的安全问题,然后将答案用作盐的想法。或者甚至可以用两个或多个单词/数字等来回答。

当然,我需要设计一些重复可能性很小的东西——比如——用户母亲的娘家姓。在我们 2000 年强大的社区中,完全相同的名字的可能性极小。并且选择的密码和安全问题的答案相同的可能性甚至更小。但是,这样的问题在答案中必然至少有一个空格。另一个想法是询问母亲的出生日期并去掉日期分隔符。

问题1:这是一个足够体面的盐渍吗?

问题2:盐可以有空格吗?还是斜线?还是连字符?

问题 3:如果 Salts 中不允许使用空格(或斜杠和连字符),是否可以在输入用作 salt 之前对输入执行某种空格(或斜杠和连字符)剥离?

问题 4:这是否可以打开任何明显的安全漏洞?

4个回答

你希望盐是独一无二的。您也不希望盐“暴露”,因为您会将其“按原样”以明文形式存储在数据库服务器上。盐不一定要保密,但如果您在未受保护的情况下存储一些他们认为应该保密的价值,人们可能会感到紧张——这包括他们母亲的娘家姓,这显然被一些美国银行用作身份验证机制。

在服务器端确保盐的唯一性很容易:只需生成足够长的随机字节序列。随机性不是唯一性,但它同样适用于压倒性的概率。好的密码散列函数可以使用任何字节序列作为盐。密码散列函数的良好实现甚至会为您正确生成盐,并将其包含在它们的输出中,因此您不必关心它(这通常是bcrypt发生的);在这种情况下,忘记这个答案和你的问题,让图书馆完成它的工作。

要求用户回答他自己的盐是一个坏主意。首先,它是技术性的,可以假设大多数用户对盐是什么一无所知;他们中的很多人会变得紧张。此外,当用户确实了解盐是什么时,他们就知道好盐是随机盐;人类用户没有很好地产生随机性(这不是人类大脑擅长的部分)。另一方面,你的服务器可以做随机性。最后,您不能指望人类用户来强制执行唯一性——特别是当用户更改密码时,他不会更改他母亲的娘家姓,因此这是唯一性不可避免的失败。


编辑:如果您的编程语言提供UUID,也称为GUID(区别是拜占庭),那么这些对盐有好处。例如,在 .NET 中,只需调用System.Guid.NewGuid(). 有多种方法可以创建此类值,但它们都针对全球唯一性(它们可能是可预测的,但这对于盐来说不是问题)。“方法4”实际上是122位的随机性。生成盐的最佳方法是让密码散列库代码来做,但如果你必须使用一个自己不做的库,那么使用系统提供的 UUID 是一种体面的省力方法。

盐用于帮助防止使用彩虹表,并要求攻击者分别攻击每个散列。这仅在无法为整个盐空间制作彩虹表时才有效。

用户选择的盐 a) 很可能不是唯一的,即使是在本地也是如此;b) 与随机选择的值相比,它很可能是一个可以在彩虹表数据库中找到的值。这两者都导致盐的有效性大大降低,因为它们简化了对哈希的攻击。

虽然盐不需要是随机的,但它确实需要是全局唯一的,这样才能使用彩虹表数据库。随机性是确保这一点的最简单方法,尽管其他可行的衍生盐的选择确实有效。

没有理由使用用户输入,只需使用随机数并将其与用户记录一起存储在数据库中就可以了。这不会对安全性产生负面影响,因为盐不必是唯一的,它只需要使用不可行的预先计算的彩虹表。

正如特里在他的回答中所说,对盐的唯一要求是每个密码都是唯一的。因此,我只会生成一个至少 16 个字节长的随机字节串(确保使用操作系统的随机生成器,而不是一些古怪的 DIY 实现)。你母亲的娘家姓可能实际上很可能(没有那么多不同的名字,也许只有一千个)重新出现,你自己生成随机字节的可能性更大。

请记住,您可以在密码旁边存储盐纯文本,盐不被视为秘密。

盐的唯一要求是它是全球唯一的。如果您有信心可以达到此要求,请务必继续。

不过想一想,您提出的方案究竟提供了哪些现有的标准方法来获取几个字节的随机数据?为什么你想通过要求另一个输入来惹恼你的用户?不要为您自己和您的用户增加更多的复杂性。坚持使用通常由任何体面的密码散列库自动处理的标准方法。