时间()是好盐吗?

zmo*_*mol 56 php security passwords hash salt

我正在看一些我自己没有写过的代码.代码尝试使用SHA512散列密码并仅使用time()盐作为密码.是time()太简单盐这或者是这个代码安全吗?

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

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

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

Jac*_*cco 84

简短回答:

不,time()不是好盐.

答案很长:

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

什么是盐?

salt是固定长度的随机字节集,添加到散列算法的输入中.


为什么盐渍(或播种)哈希有用?

向散列添加随机盐可确保相同的密码将产生许多不同的散列.salt通常与散列函数的结果一起存储在数据库中.由于以下几个原因,对哈希进行盐析是很好的:

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


盐不需要保密.

salt不是一个秘密密钥,而是通过使哈希函数特定于每个实例来使"盐"起作用.使用salted哈希,没有一个哈希函数,但每个可能的盐值都有一个哈希函数.这可以防止攻击者攻击N个散列密码的次数少于攻击一个密码的N倍.这是盐的重点.
"秘密盐"不是盐,它被称为"密钥",它意味着您不再计算哈希值,而是计算消息验证码(MAC).计算MAC是一项棘手的业务(比简单地将一个键和一个值拼接到一个哈希函数中要复杂得多)并且它完全是一个非常不同的主题.

对于使用它的每个实例,盐必须是随机的.这可确保攻击者必须分别攻击每个salted哈希.
如果你依赖你的盐(或盐算算法)是秘密的,你进入安全通过晦涩的领域(将无法工作).最有可能的是,你没有从盐保密中获得额外的安全性; 你只是得到了温暖的模糊安全感.因此,它不会让您的系统更安全,而只会让您远离现实.


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

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

尝试从一些"大概是唯一的"数据中获取盐是很诱人的,例如用户ID,但是由于一些令人讨厌的细节,这些方案经常会失败:

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

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

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

使用从加密安全,不可预测的PRNG获得的随机盐可能是某种矫枉过正,但至少它可以证明可以保护您免受所有这些危害.这不是为了防止攻击者知道单个盐是什么,而是为了不给他们提供大量,可用于大量潜在目标的大目标.随机选择使目标尽可能薄.


结论:

使用随机,均匀分布的高熵盐.无论何时创建新密码或更改密码,都要使用新的盐.将盐与散列密码一起存储.喜欢大盐(至少10个字节,最好是16个或更多).

盐不会将错误的密码变成好的密码.它只是确保攻击者至少为他打破的每个错误密码支付字典攻击价格.


有用的资料来源:
stackoverflow.com:用于密码哈希的非随机盐
Bruce Schneier:实用密码学(书籍)
Matasano安全性:足够使用Rainbow Tables
usenix.org:自1976年以来Unix crypt使用盐
owasp.org:为什么要加盐
openwall.com:

免责声明:
我不是安全专家.(虽然这个答案由Thomas Pornin审查)
如果有任何安全专业人员发现错误,请评论或编辑此维基答案.


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

如果由于某种原因你无法访问上面提到的随机源,在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);
}
?>
Run Code Online (Sandbox Code Playgroud)

  • 值得注意的是PHP 5.3中的(标准)OpenSSL扩展中的一个新函数:[`openssl_random_pseudo_bytes()`](http://php.net/openssl_random_pseudo_bytes)作为一个快速,有效,经过良好测试的熵生成器. (2认同)
  • 长答案并没有直接说明为什么时间戳是一个糟糕的选择。通读一遍,时间戳的唯一问题似乎是它是可预测的。攻击者可以创建一个针对特定时间创建的所有用户的表,但只有同时创建多个用户时才会出现问题。如果情况并非如此,那么时间戳看起来就像随机盐*一样好。那么真正的答案似乎是“没有必要,因为获得一个可以防止这种攻击的随机值是微不足道的”?*虽然 php time() 具体可能不是 (2认同)
  • @ clockw0rk不,时间从来都不是好盐,因为时间分布不均匀。因此,攻击者只需要攻击所有可能值的子集。 (2认同)