密码盐和随机性

信息安全 哈希 md5
2021-09-04 08:22:26

好的,所以我知道用户是那种喜欢使用一个密码并使其简短易记的野兽(如“小狗”)。如果我理解正确,这就是我们使用密码盐的原因之一。它们增加了长度和某种程度的随机性。我的问题是如何生成它们。我在最近(仍然完全是内部)项目中生成盐(和密码哈希)的方式是执行以下操作:

  1. 获取自纪元以来的时间(以秒为单位)
  2. 获取进程运行的时间(操作系统允许的粒度)
  3. 创建上述两个结果的 MD5 哈希
  4. 以不同的组合附加我现在拥有的 4 个字符串
  5. 将此存储为纯文本
  6. 以几种方式附加密码和盐
  7. 用于创建密码哈希的 SHA-512 哈希

这足够随机吗?它增加了足够的熵吗?我最近读到我需要一个更强大的哈希算法(查看 bcrypt)并且需要多个哈希(1000+)才能足够安全,但这不是问题的重点。

2个回答

这似乎被误导了。

来自任何来源的以秒为单位的时间几乎没有任何熵,并且几乎可以立即猜测。如果您的操作系统允许运行进程的微秒粒度,那么您将从较低的位获得 4 或 5 位的熵,但如果有人找到获得准确系统正常运行时间的方法,则要少得多。

然后你在谈论 MD5,在这种情况下它并不是很有用。它所做的一切给你的印象是你让它变得更加随机,但实际上并没有让它变得随机。实际上,您只有几个相互依赖的整数(处理时间总是与系统正常运行时间同步)并且完全是非随机的。您的系统几乎肯定会以一种或另一种形式泄露其正常运行时间。实际上,您最好使用PHP 之类的LCGrand(),因为无法轻易猜出内部状态。

这种随机数生成方法很糟糕,因为它根本不是随机的,并且可以预测。然而,盐实际上并不需要特别随机,它们只需要是唯一的;他们只是为了防止彩虹桌攻击。不可预测性会有所帮助(请参阅“如何储存盐?”),但并非完全需要。无论如何,使盐难以预测有一些好处。

如果您在 Linux 上,请从中读取一些字节/dev/urandom以生成盐 - 除了获取这些字节并使用它们之外,您不需要做任何其他事情,因为它们已经是强随机数。

如果不是,您可以生成盐作为SHA256(username || email || time || mt_rand())where||表示连接,time是当前系统时间的分辨率,并且mt_rand()是您的编程语言默认库中可用的任何随机生成器的输出值。在 PHP 中你应该使用mt_rand而不是rand,因为它有更好的特性。这为盐提供了足够的熵,因此很难远程猜测,特别是考虑到重用用户名和电子邮件组合的机会有限。

对于存储密码,您绝对应该使用 PBKDF2 或 bcrypt。单次使用加密哈希函数不足以保护您免受暴力攻击,尤其是当如今几乎每个人都拥有兼容 OpenCL 的 GPU 时。

实际上,盐不必是随机的。它必须是独一无二的这是全球唯一性(对所有时间和世界各地的所有服务器都是唯一的),实现唯一性的最简单方法是使用随机性:使用加密强的随机生成器生成 16 个字节(或更多),以及您命中的概率已经在别处使用的盐值小到可以忽略不计。

随机性很难。你介绍的是自制的弱随机数生成器和自制的弱密码散列机制的组合。生成盐正确方法/dev/urandom是要求系统伪随机数生成器为您完成(在类 Unix 系统上、CryptGenRandom()在 Windows 上、System.Security.Cryptography.RNGCryptoServiceProvider在 .NET 上......)。然后,将盐与适当的密码散列系统(如bcryptPBKDF2 )一起使用。大多数 bcrypt 实现实际上会为您生成盐,所以这会更好。