5

几年前,我在 stackoverflow 上询问了如何使 PHP 密码存储安全。主要答案建议使用以下散列算法:

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

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

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

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

4

3 回答 3

2

这完全是假设随机数是盐……

如果你说的随机数是指盐,那么是的,这需要制作更多的彩虹表。通常一次加盐超过 20 个字符就足够了,但是对于极端的安全条件,您需要为每个密码设置一个新的随机加盐。

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

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

但总的来说,制作彩虹桌需要相当长的时间。因此,如果您想出一种很长的盐,那么它的彩虹表可能就不存在了。

于 2011-01-08T18:15:33.060 回答
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. 归还钥匙

我觉得这可能是最好的方法。也许我太偏执了?

于 2011-01-13T19:46:05.077 回答
0

为了存储足够的密码以供使用:

sha512(salt + password)

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

在密码之前放置盐将有助于隐藏哈希模式,以防某些用户具有相同的密码。

不需要Nonce ,因为它是为了防止回复攻击。这种保护在您的架构中是不可能的。

使用HMAC来防止冲突是没有用的,因为 a) 我们使用哈希而不是 MAC,b) 使 SHA-512 的冲突概率为 50%,您需要计算大约 2^256 个值。而 2^256 是真正的天文数字。

于 2011-01-08T21:03:26.167 回答