time()是一种好盐吗?

2022-08-30 09:40:11

我正在查看一些我自己没有编写的代码。该代码尝试使用SHA512对密码进行哈希处理,并像盐一样使用。这太简单了还是这个代码安全?time()time()

感谢您的回答和评论。我将在这里为新读者总结一下:

  • 每个用户的盐应该不同,因此如果2个用户同时注册,他们的盐将不是唯一的。这是一个问题,但不是一个大问题。
  • 但是盐不应该以任何方式与用户相关,所以time()不是一个好的盐。
  • "使用随机的,均匀分布的,高熵的盐。--这很拗口,那么什么代码可能会产生盐呢?random, evenly distributed, high entropy

好吧,那么我用一个随机字符串32 char long替换time()怎么样。随机字符串可以通过在一组字母字符上循环32次来生成。这听起来不错吗?


答案 1

简短的回答:

不,不是好盐。time()

长答案:

从我对Salt Generation和开源软件的回答中复制

什么是盐?

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


为什么腌制(或播种)哈希值有用?

向哈希添加随机盐可确保相同的密码将生成许多不同的哈希。盐通常与哈希函数的结果一起存储在数据库中。腌制哈希值是件好事,原因有很多:

  1. 腌制大大增加了预先计算的攻击(包括彩虹表)的难度/成本)
  2. Salting确保相同的密码不会产生相同的哈希值。这可确保您无法确定两个用户是否具有相同的密码。而且,更重要的是,您无法确定同一个人是否在不同系统中使用相同的密码。
  3. 盐渍增加了密码的复杂性,从而大大降低了字典生日攻击的有效性只有当盐与哈希分开存储时,这才是正确的)。
  4. 适当的腌制大大增加了预计算攻击的存储需求,直到它们不再实用。(8 个字符区分大小写的字母数字密码,16 位 salt,散列为 128 位值,将占用不到 200 EB 而不减少彩虹)。


盐没有必要是秘密的。

盐不是密钥,而是盐通过使哈希函数特定于每个实例来“工作”。使用盐渍哈希,没有一个哈希函数,而是每个可能的盐值都有一个。这可以防止攻击者攻击 N 个散列密码,而攻击成本不到攻击一个密码的 N 倍。这就是盐的要点。
“秘密盐”不是盐,它被称为“密钥”,这意味着您不再计算哈希值,而是消息身份验证代码(MAC)。计算MAC是一项棘手的业务(比简单地将密钥和值组合成哈希函数要棘手得多),而且它是一个完全不同的主题。

盐对于使用它的每个实例必须是随机的。这确保了攻击者必须单独攻击每个盐渍哈希。
如果你依靠你的盐(或盐渍算法)是秘密的,你进入了通过晦涩的安全领域(不会起作用)。最有可能的是,您没有从盐的秘密中获得额外的安全性;你只是得到温暖模糊的安全感。因此,它不会使您的系统更安全,而只会分散您对现实的注意力。


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

从技术上讲,盐应该是独一无二的。盐的要点是每个散列密码都是不同的。这意味着全世界。由于没有按需分配唯一盐的中央组织,我们必须依靠下一个最好的东西,即使用不可预测的随机生成器进行随机选择,最好是在足够大的盐空间内使碰撞变得不可能(两个实例使用相同的盐值)。

尝试从一些“大概是唯一的”数据(例如用户ID)中导出盐是很诱人的,但是由于一些令人讨厌的细节,这样的方案经常失败:

  1. 例如,如果您使用用户 ID,一些攻击不同系统的坏人可能只是汇集他们的资源并为用户 ID 1 到 50 创建预先计算的表。用户 ID 在系统范围内是唯一的,但不是全球性的

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

  3. 唯一性也是暂时的。有时,用户会更改其密码。对于每个新密码,必须选择一个新盐。否则,攻击者获取了旧密码的哈希值,而新密码的哈希值可能会尝试同时攻击两者。

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


结论:

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

盐不会把一个坏密码变成一个好密码。它只是确保攻击者至少会为他破解的每个坏密码支付字典攻击价格。


有用的来源:
stackoverflow.com:密码哈希
的非随机盐 Bruce Schneier:实用密码学(书)
Matasano安全性:足够彩虹表
usenix.org:Unix密码自1976
年以来一直使用盐 owasp.org为什么要添加盐
openwall.com盐类

免责声明:
我不是安全专家。(虽然这个答案是由托马斯·波尔宁审查的)
如果任何安全专业人员发现错误,请发表评论或编辑此wiki答案。


至于什么似乎是你的随机盐
的良好来源,另请阅读:随机数生成最安全的种子是什么?
在没有专用的、基于硬件的随机生成器的情况下,获取随机数据的最佳方式是询问操作系统(在Linux上,这被称为或[两者都有优点和问题,选择你的毒药];在Windows上,调用/dev/random/dev/urandomCryptGenRandom())

如果由于某种原因您无法访问上述随机源,则可以在PHP中使用以下函数:
来自phpass v0.3的源

<?php
/**
 * Generate pseudo random bits
 * @copyright: public domain
 * @link http://www.openwall.com/phpass/
 * @param int $length number of bits to generate
 * @return string A string with the hexadecimal number
 * @note don't try to improve this, you will likely just ruin it
 */
function random_bits($entropy) {
    $entropy /= 8;
    $state = uniqid();
    $str = '';
    for ($i = 0; $i < $entropy; $i += 16) {
        $state = md5(microtime().$state);
        $str .= md5($state, true);
    }
    $str = unpack('H*', substr($str, 0, $entropy));
    // for some weird reason, on some machines 32 bits binary data comes out as 65! hex characters!?
    // so, added the substr
    return substr(str_pad($str[1], $entropy*2, '0'), 0, $entropy*2);
}
?>

答案 2

更新

这不是一种非常好的盐,但可能足以击败所有人,除了最坚定和足智多谋的攻击者。对好盐的要求是:

  • 每个用户不同
  • 足够长(至少是字母数字8个字符),以使盐和(可能较弱的)密码的串联太长而无法进行暴力攻击。

time()值实际上不够长,因为它们有 10 个字符,但只有数字。

此外,有时,当两个用户在同一秒内创建时,它们可能会获得相同的值。但是,如果您遇到在同一秒内自动创建许多用户的情况,则只会出现问题。

无论如何,比完美的盐更重要的是使用良好的哈希函数,SHA512是我们目前最好的哈希函数之一。


推荐