【问题标题】:md5(uniqid) makes sense for random unique tokens?md5(uniqid) 对随机唯一令牌有意义吗?
【发布时间】:2011-02-05 08:00:24
【问题描述】:

我想创建一个令牌生成器,它生成用户无法猜到且仍然唯一的令牌(用于密码重置和确认码)。

我经常看到这段代码;有意义吗?

md5(uniqid(rand(), true));

根据comment uniqid($prefix, $moreEntopy = true) 产生

前 8 个十六进制字符 = Unixtime,后 5 个十六进制字符 = 微秒。

不知道$prefix-参数是怎么处理的..

因此,如果您不将 $moreEntopy 标志设置为 true,它会给出可预测的结果。


问题: 但是,如果我们将uniqid$moreEntopy 一起使用,那么用md5 对其进行散列对我们有什么好处?是否优于:

md5(mt_rand())

edit1:我会将此标记存储在具有唯一索引的数据库列中,因此我将检测列。可能感兴趣/

【问题讨论】:

    标签: php security hash random passwords


    【解决方案1】:

    首先,这种过程的范围是创建一个密钥/哈希/代码,这对于一个给定的数据库来说是唯一的。在特定时刻为整个世界创造独特的东西是不可能的。 话虽如此,您应该使用自定义字母创建一个普通的可见字符串,并根据您的数据库(表)检查创建的代码。 如果该字符串是唯一的,那么您将对其应用md5(),并且任何人或任何脚本都无法猜到。 我知道,如果你深入研究密码生成的理论,你可以找到很多关于这种代码生成的解释,但是当你真正使用它时,它真的没有那么复杂。

    这是我用来生成一个简单的 10 位唯一代码的代码。

    $alphabet = "aA1!bB2@cC3#dD5%eE6^fF7&gG8*hH9(iI0)jJ4-kK=+lL[mM]nN{oO}pP\qQ/rR,sS.tT?uUvV>xX~yY|zZ`wW$";
    $code = '';
    $alplhaLenght = strlen($alphabet )-1;
    for ($i = 1; $i <= 10; $i++) {
        $n = rand(1, $alplhaLenght );
        $code .= $alphabet [$n];
    }
    

    这里有一些生成的代码,虽然你可以自己运行它来看看它是否有效:

    SpQ0T0tyO%
    乌恩[MU][.
    D|[ROt+Cd@
    O6I|w38TRe

    当然,可以对它进行很多“改进”,使其更加“复杂”,但如果你对此应用md5(),它就会变成,比如说“不可猜测” ” 。 :)

    【讨论】:

      【解决方案2】:

      我知道这个问题很老,但它出现在 Google 中,所以...

      正如其他人所说,rand()mt_rand()uniqid() 并不能保证您的唯一性……甚至不应使用 openssl_random_pseudo_bytes(),因为它使用了 deprecated features of OpenSSL

      您应该使用random_bytes()(在 PHP7 中引入)来生成随机散列(与 md5 相同)。生成与 MD5 长度相同的哈希:

      bin2hex(random_bytes(16));

      如果您使用的是 PHP 5.x,您可以通过包含 random_compat library 来获得此功能。

      【讨论】:

      【解决方案3】:

      rand() 是一种安全隐患,绝不能用于生成安全令牌:rand() vs mt_rand()(查看类似“静态”的图像)。但是这些生成随机数的方法都不是密码安全的。要生成安全密钥,应用程序需要访问平台、操作系统或硬件模块提供的CSPRNG

      在 Web 应用程序中,安全机密的良好来源是对熵池(例如 /dev/urandom)的非阻塞访问。自 PHP 5.3 起,PHP 应用程序可以使用openssl_random_pseudo_bytes(),Openssl 库会根据您的操作系统选择最佳熵源,在 Linux 下这意味着应用程序将使用/dev/urandom。这个code snip from Scott is pretty good

      function crypto_rand_secure($min, $max) {
              $range = $max - $min;
              if ($range < 0) return $min; // not so random...
              $log = log($range, 2);
              $bytes = (int) ($log / 8) + 1; // length in bytes
              $bits = (int) $log + 1; // length in bits
              $filter = (int) (1 << $bits) - 1; // set all lower bits to 1
              do {
                  $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
                  $rnd = $rnd & $filter; // discard irrelevant bits
              } while ($rnd >= $range);
              return $min + $rnd;
      }
      
      function getToken($length=32){
          $token = "";
          $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
          $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
          $codeAlphabet.= "0123456789";
          for($i=0;$i<$length;$i++){
              $token .= $codeAlphabet[crypto_rand_secure(0,strlen($codeAlphabet))];
          }
          return $token;
      }
      

      【讨论】:

      • md5() in this case is being used to obscure the time that it was created which is a legitimate use 这听起来像是答案。
      • 我有一个服务器进程需要获取表单数据并将其保存为 uniquetoken.xml。我已经准备好创建 xml 文件的表单。到目前为止,我用每个 mmddyy.xml 命名它们。我怎么能用 md5(uniqid(mt_rand(), true)); 替换它?
      • 这是不安全的。请参阅 Scott 的回答。
      • @ChocoDeveloper "/dev/urandom 是迄今为止 Web 应用程序的最佳熵源。"
      • 我说的是您提供的代码的 sn-p,并标记为“出于大多数安全目的,这是一个很好的令牌”,可供新手使用。此外,/dev/urandom 也不是“最好的熵源”,因为它是非阻塞的。 openssl_random_pseudo_bytes() 的存在是有原因的。
      【解决方案4】:

      这是我发现的另一个问题的副本,该问题在此问题之前几个月被问到。这是问题和我的答案的链接:https://stackoverflow.com/a/13733588/1698153

      我不同意接受的答案。根据PHP自己的网站"[uniqid] does not generate cryptographically secure tokens, in fact without being passed any additional parameters the return value is little different from microtime(). If you need to generate cryptographically secure tokens use openssl_random_pseudo_bytes()."

      我认为答案比这更清楚,uniqid 不安全。

      【讨论】:

      • 赞成,所以人们应该真正检查链接而不是接受的答案。
      • 斯科特,我不知道那个老问题,对不起。我猜openssl_random_pseudo_bytes() (PHP 5 >= php 5.3) 在询问时并不总是可用的。你是对的,接受的答案已经改变,并且指的是你此刻的答案,所以其他人不会被误导。
      【解决方案5】:

      几年前我遇到了一个有趣的想法。
      在数据库中存储两个哈希值,一个使用 md5($a) 生成,另一个使用 sha($a) 生成。然后检查这两个值是否正确。关键是,如果攻击者破坏了您的 md5(),他将无法在不久的将来破坏您的 md5 和 sha。
      问题是:该概念如何与您的问题所需的令牌生成一起使用?

      【讨论】:

      • 不会仅仅将它们与像 _ 或 - 这样的字符串胶合起来就足以创建一个更不可能串通的合并令牌吗?您不需要将它们保存在单独的数据库字段中。您可以将它们保持为合并状态。如果您需要对它们进行任何操作,您只需使用函数处理字符串即可。这样,组合字符串可以用作任何需要进程的唯一字符串的令牌,例如会话密钥或密码重置请求或许多其他事情。
      【解决方案6】:

      要回答您的问题,问题是您不能拥有一个保证随机且唯一的生成器本身就是随机的,即md5(mt_rand()) 可能导致重复。你想要的是“随机出现”的独特价值。 uniqid 给出唯一的 id,rand() 附加一个随机数,使其更难猜测,md5 掩盖结果,使其更难猜测。没有什么是不可猜测的。我们只需要让它变得如此艰难,以至于他们甚至都不想尝试。

      【讨论】:

      • 您说“md5 掩盖了结果,使其更难猜测”。所以 uniqueid 会生成一个有点随机的结果,它是唯一的。你说的掩蔽到底是什么意思?如果我遵循这个想法,那么md5(md5(uniqid(rand(), true) 将意味着更多的掩蔽,但它更糟糕,对吧?
      • @Excpetion e,双 md5() 哈希不会提高该系统的安全性。
      【解决方案7】:

      定义“独特”。如果您的意思是两个令牌不能具有相同的值,那么散列是不够的 - 它应该由唯一性测试支持。您提供具有唯一输入的哈希算法这一事实并不能保证唯一的输出。

      【讨论】:

      • unique = 确实没有相同的值。每个令牌都与一个唯一的电子邮件地址相关联。也许我们可以使用它来使随机令牌唯一。我仍然不确定最好的方法是什么。
      【解决方案8】:

      MD5 是一种不错的算法,用于生成数据相关 ID。但如果您有多个具有相同比特流(内容)的项目,您将产生两个相似的 MD5“ID”。

      因此,如果您只是将其应用于rand() 函数,并且保证不会两次创建相同的数字,那么您是非常安全的。

      但为了更强大的密钥分布,我个人会使用 SHA1 或 SHAx 等'...但您仍然会遇到相似数据导致相似密钥的问题。

      【讨论】:

      • 旧帖,但rand()如何保证不创建两次相同的号码?
      猜你喜欢
      • 2016-01-24
      • 1970-01-01
      • 2014-04-16
      • 1970-01-01
      • 2012-07-27
      • 2015-02-04
      • 2012-09-13
      • 2014-06-01
      • 1970-01-01
      相关资源
      最近更新 更多