使用HMAC + nonce的PHP密码存储 - nonce随机性是否重要?

时间:2011-01-08 18:08:10

标签: php security hash hmac password-storage

几年后,我在stackoverflow上询问了如何使PHP密码存储安全。 main answer建议使用以下散列算法:

function hash_password($password, $nonce) {
  global $site_key;
  return hash_hmac('sha512', $password . $nonce, $site_key);
}

答案建议使用随机随机数。有一个随机的随机数比简单的唯一随机数有什么优势吗?

例如,每个用户都可以拥有自己的ID,但不会发生变化。但是,我们假设用户ID是顺序的(使用MySQL的自动增量功能构建),因此不是随机的。用户ID是一个好的nonce还是随机性很重要?

现在,每个用户都可以选择一个用户名。每个用户都有自己的用户名,该用户名不会更改,两个不同的用户不能拥有相同的用户名。 用户名仍然不是随机的,但它们也不是顺序的。用户名是否足够好作为nonce?它会比使用用户ID更好吗?

3 个答案:

答案 0 :(得分:2)

这一切都在假设一个NONCE是盐...

如果用nonce表示盐,那么是的,需要更多的彩虹表。通常,超过20个字符的盐就足够了,但是对于极端安全条件,您需要为每个密码添加一个新的随机盐。

慢速哈希http://www.php.net/manual/en/function.hash.php#89574也是不错的选择,没有讽刺。但我喜欢成熟。

没有看到你的回复的下半部分。详细说明:Nonce用于防止使用彩虹表。 ID是否有效仅取决于ID的长度。随机性在技术上并不重要,但只需要更多的彩虹表。例如,假设您使用字符“a”作为随机数,密码长度为2个字符,则必须创建a-aa,a-ab a-ac等的彩虹表。如果你每次都使用一个随机的,那么'a'的所有排列都必须完成+其他随机字符的所有变换。

但总的来说制作彩虹表需要相当长的时间。因此,如果你想出一个很长的盐,很可能它的彩虹表不存在。

答案 1 :(得分:2)

我发现在网上写了一篇关于这个主题的相当不错的教程。我不太清楚谷歌在哪里找到了它,但让我看看我是否可以将自己的功能完全打破,因为它就在我面前......

首先是该函数,它可以创建任意大小的密钥长度。我冒昧地评论它......

function pbkdf2($password,$salt,$iter_count = 1500,$key_length = 32,$algorithm = 'sha512') 
{
    /*
      @param string password -- password to be encrypted
      @param string salt -- salt to encrypt with
      @param int iter_count -- number of times to iterate blocks
      @param key_length -- length of key to return
      @param $algorithm -- algorithm to use in hashing

      @return string key
    */

    //determine the length of the hahs
    $hash_length = strlen(hash($algorithm,NULL,TRUE));
    //determine the number of key blocks to compute
    $key_blocks = ceil($key_length/$hash_length);
    //initialize key
    $key = '';

    //create the key itself
    //create blocks
    for($block_count = 1;$block_count <= $key_blocks;$block_count++)
    {
        //initalize hash for this block
        $iterated_block = $block = hash_hmac($algorithm,$salt.pack('N',$block_count),$password,TRUE);
        //iterate blocks
        for($iterate = 1;$iterate <= $iter_count;$iterate++)
        {
            //xor each iterate
            $iterated_block ^= ($block = hash_hmac($algorithm,$block,$password,TRUE));
        }
        //append iterated block
        $key .= $iterated_block;
    }
    //return the key
    return substr($key,0,$key_length);
}
  1. 它首先要弄清楚哈希的长度。
  2. 接下来,它确定指定密钥长度需要多少个密钥块
  3. 然后初始化哈希(键)以返回
  4. 设置将创建每个块的for循环
  5. 获取块的初始哈希值,其中块计数器以二进制形式附加到salt
  6. 开始循环迭代块$ iter_count次(创建自己的哈希)
  7. 每次迭代XOR并将其附加到$ iterated_block(xor以前的哈希值到当前)
  8. XOR循环结束
  9. 将$ iterated_block附加到每个块的$ key
  10. 阻止循环完成
  11. 返回密钥
  12. 我觉得这可能是最好的方法。也许我太偏执了?

答案 2 :(得分:0)

用于存储足以使用的密码:

sha512(salt + password)
每个用户

salt 随机且唯一。随机盐将使预先计算的哈希表攻击变得不可能:每个用户都需要自己计算的哈希表。如果你不使用随机盐,那么预先计算的表存在的可能性会更高。

在密码之前定位salt 将有助于隐藏哈希模式,以防某些用户拥有相同的密码。

不需要

Nonce ,因为它是用于防止回复攻击。您的架构中无法实现此保护。

使用 HMAC 来防止冲突是没用的,因为a)我们使用哈希不用于MAC,b)使SHA-512 you need to calculate的冲突概率为50%约2 ^ 256值。并且2 ^ 256是真正的天文数字。