盐哈希值应该从哪里来?


12

当将盐值添加到哈希值中(例如无法以纯文本形式存储的密码)时,获得盐值的最佳位置是什么?对于上下文,让我们假设这是网页登录时的密码。


@DevArt,我认为它更适合这里,因为它需要一个非常主观的答案。可以从任何地方提取盐值,所以我问“您认为从哪里提取盐值的最安全位置是:客户端还是服务器?”
Morgan Herlocker 2011年

Answers:


7

我通常created TIMESTAMP在用户表中有一列,这样我就可以看到用户何时注册。我不喜欢为Salt添加其他列,因此我将timestamp列用作salt:

SHA1(password + created)

然后,我假设当用户再次登录时,您在重新进行验证时基于用户名拉日期吗?
Morgan Herlocker 2011年

1
@Prof:是的,如果您有专门用于盐的列,则与您使用的方法相同,因此在该角度上没有区别。
乔纳斯

7

有关系吗?

盐有两个目的。这使得使用预先加密的大型表(“彩虹表”)变得不切实际,并且使相同的密码在哈希列表中看起来有所不同。使相同的密码看起来不同有助于避免多个人使用一个特定密码的问题,这大概是一个常见的弱密码。

因此,每个帐户都应有其自己独特的盐,并且在不会出现一组可能发生的盐的意义上,盐也不应过于可预测。(例如,如果许多站点从1开始并计数,那么坏人可以构建包括低盐的彩虹表。)除了一般不可预测的以外,它们在任何意义上都不必是随机的。它们没有比散列本身更秘密,因此它们不需要特别不可猜测。

使用任何方便的方法生成盐。如果与帐户数量相比有很多潜在的盐值(早期的Unix系统经常使用两个字节,可能的数目为65536),则半随机分配几乎永远不会给出重复的盐值。


1
我通常看到第二个问题-相同的密码看起来有所不同-通过串联用户名,盐和密码并散列整个字符串来解决。这样就无需为每个帐户生成唯一的盐。
贾斯汀·凯夫

1
@Justin:有趣的是,我从未见过将用户名用作哈希的一部分,但这确实是添加一些熵的好方法。不过,我仍然会使用伪随机盐,只是因为生成一个盐不会花费太多。
Matthieu M.

2
@Matthieu缺点是必须将其存储在某个地方,并且如果事务双方都需要它,则还必须发送它。有了用户名,双方都已经知道了。
马修·弗雷德里克

2
@Justin:在这种情况下,您使用的是用户名。它满足了盐的两个目的:使彩虹表不切实际,使相似的密码看起来不同。
David Thornley,

@David-是的,您可以将其视为用户名的一部分。我仍然想要额外的盐,以便攻击者无法使用彩虹表查找用户名/密码组合。如果没有明确的限制,您只是在增加攻击者需要从彩虹表中获取的字符串的大小,增加其用户名的长度(该名称可能很短,或者完全小写或完全大写)。除非您的站点足够大,攻击者将生成特定于站点的彩虹表,否则恒定的盐足以阻止彩虹表攻击。
贾斯汀·凯夫

3

每次您要存储新密码(注册,密码重置,密码更新)时,一种好的方法是:

  • 产生新的盐
    • 使用加密安全的伪随机数生成器
    • 使用适当大小的盐-一个好的值是基础哈希算法的块大小(可能是SHA-256)
  • 生成一个新的密码令牌
    • 使用盐作为hmac密钥,从基础哈希算法(可能是SHA-256)创建hmac函数
    • for i in (0...65536) { password = hmac(password) }
    • hmac函数的迭代应用程序的结果是密码令牌
  • 存储盐和密码令牌
    • 不存储原始密码
    • 可选地存储基础哈希算法和扩展以提高可发现性

1

利用框架。在.NET中,您可以使用RNGCryptoServoiceProvider ...

        // If salt is not specified, generate it on the fly.
        if (saltBytes == null)
        {
            // Define min and max salt sizes.
            int minSaltSize = 4;
            int maxSaltSize = 8;

            // Generate a random number for the size of the salt.
            Random  random = new Random();
            int saltSize = random.Next(minSaltSize, maxSaltSize);

            // Allocate a byte array, which will hold the salt.
            saltBytes = new byte[saltSize];

            // Initialize a random number generator.
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

            // Fill the salt with cryptographically strong byte values.
            rng.GetNonZeroBytes(saltBytes); 
        }

其他框架应该具有可以利用的相似类。为了实现随机性,软件通常要雇用用户,而不是Random如上所述。TrueCrypt会采用在指定区域随机移动鼠标以提供盐分的选项。它归结为您的特定需求和安全级别;因为你的盐简直可以!@#$%


1

您将生成一个盐服务器端,并在其创建后将其分配给用户帐户。最好使用框架提供的一些加密生成API,但原则上任何顺序都可以。

通常情况是这样存储的:

User
-------------------
ID
Username
PasswordHashWithSalt

例:

PasswordHashWithSalt =

A15CD9652D4F4A3FB61A2A422AEAFDF0DEA4E703 j5d58k4b56s8744q


根据什么分配它?它是否不必来自保留下来的某个值,以便在用户创建后重新登录时可以复制它?
Morgan Herlocker 2011年

“分配”是指为每个用户名/密码对(帐户)生成一个盐,并将其存储在数据库中。当需要执行登录时,可以使用存储的盐来检查内容。

1

在当今时代,仅使用bcrypt并阅读有关常规散列的文章并不是认真的保护。

考虑使用SDR零知识密码协议,该协议具有大量开源库,并且没有专利。

特别提款权需要食盐,而获得食盐的最佳场所是客户。定时击键,鼠标移动,对环境变量,随机数进行哈希处理,在其temp文件夹中创建文件的时间,以一种无法预测的方式使它们的末端远离服务器。SDR会花一些大功劳和用户密码,然后生成一个验证者密钥。您无需存储密码,它永远不会离开他们的计算机,但是您可以验证他们是否具有与验证程序密钥和盐一起使用的密码。它不受中间人攻击和字典攻击。为了确保安全,请加密数据库列中的密钥和盐。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.