【问题标题】:How unique is the php session idphp会话ID的唯一性
【发布时间】:2010-09-13 09:53:45
【问题描述】:

php 会话 ID 的唯一性如何?我从读过的各种内容中得到的印象是,我不应该依赖两个用户永远不会获得相同的 sessionid。不是 GUID 吗?

【问题讨论】:

    标签: php session guid


    【解决方案1】:

    不,会话 ID 不是 GUID,但两个用户不应获得相同的会话 ID,因为它们存储在服务器端。

    【讨论】:

    • 可能是因为服务器端存储不能以任何方式保证唯一性。唯一性是一回事 - 如果发生冲突,无论会话存储在哪里,它都会发生冲突。
    • 不是我,感谢您的回复(以及其他人)。 -- 贾洛夫
    • 会话ID存储在服务器端和客户端。会话内容存储在服务器端。而且这个事实几乎与会话 ID 的唯一性无关。
    【解决方案2】:

    我还没有找到对此的确认,但我相信 php 在创建具有该 ID 的会话 ID 之前会检查会话 ID 是否已经存在。

    人们担心的会话劫持问题是当有人发现活跃用户的会话 ID 时。这可以通过多种方式防止,有关更多信息,您可以在 php.net 上查看 this pagethis paper on session fixation

    【讨论】:

    • ...但是如果您只是一个 php 服务器中的几个,则不能保证服务器有足够的知识来知道 sesssionID 是否已被使用。
    • 如果我在 2 个不同的 php 服务器中获得相同的会话 id 为什么会很重要?假设有 2 个不同的域,会话 cookie 只能从每个域访问..​​.?
    • 在多服务器环境中防止欺骗的最简单方法是通过 memcached 会话处理程序将会话存储在 memcached 中。问题解决了,您的用户可以在不同的服务器上反弹而不会丢失他们的东西。
    • @daremon 他说的是一个域的多个服务器。
    • 这完全不正确。 PHP 在生成新会话 ID 时不会检查现有会话 ID。查看任何 PHP 会话处理程序代码,根本没有为此目的实现任何方法。
    【解决方案3】:

    如果您想自定义生成 ID 的方式(默认情况下是通过 MD5 生成的 128 位数字),您可以安装替代的哈希生成函数。见http://www.php.net/manual/en/session.configuration.php#ini.session.hash-function

    有关 PHP 会话的更多信息,请阅读这篇出色的文章 http://shiflett.org/articles/the-truth-about-sessions,该文章还链接到有关会话固定和劫持的其他文章。

    【讨论】:

    • 准确地说,为 PHP 5.3 设置 "session.hash_function = sha512" 并达到 512 位哈希。这应该可以解决问题。在默认情况下,在高流量站点上发生冲突是很常见的。
    【解决方案4】:

    它在发货时并不是很独特。在默认配置中,它是各种事物的哈希结果,包括 gettimeofday 的结果(这并不是非常独特),但如果您担心,您应该将其配置为从 /dev/urandom 中提取一些熵,就像这样

    ini_set("session.entropy_file", "/dev/urandom");
    ini_set("session.entropy_length", "512");
    

    the code 中搜索“php_session_create_id”以了解他们正在使用的实际算法。

    编辑添加: 有一个由 pid 播种的 DFA 随机数生成器,与 usecs 中的时间混合。这不是一个确定的唯一性条件especially from a security perspective。使用上面的熵配置。

    更新:

    从 PHP 5.4.0 开始 session.entropy_file 默认为 /dev/urandom 或 /dev/arandom 如果可用。在 PHP 5.3.0 中保留了该指令 默认为空。 PHP Manual

    【讨论】:

    • 是的,当我为一个网站签订合同时,该网站必须对敌方战斗人员等具有超安全性,我实际上创建了自己的会话处理程序并直接从 random.org 提供熵数据。但是该系统的要求远远超出了大多数普通人所处理的范围;-)
    • @thomas-jensen, gettimeofday unix 时间戳,除了它以微秒表示(有时)。阅读上面链接的 php_session_create_id 方法。
    • 更改熵长度会提高随机性,但不会显着影响冲突的可能性,因为哈希仍然是相同的长度。但是,更改 session.hash_function 允许您使用更长的哈希值,例如 sha512。
    • 我觉得奇怪的是有碰撞。当然应该让 PHP 来检查该 id 下是否存在有效会话,然后生成不同的 ID ..
    • @theodore-r-smith,从公开来源获取熵是非常糟糕的做法。您应该假设您的“敌方战斗人员”也可以访问 random.org...
    【解决方案5】:

    Session_id确实可以重复,但是概率很低。如果您有一个流量公平的网站,它可能会在您的网站生命中发生一次,并且只会在一次会话中惹恼一位用户。

    这不值得关心,除非你期望为银行业建立一个非常高流量的网站或服务。

    【讨论】:

    • 我听说有很多网站发生冲突的报告。
    • 这个问题已经问了将近 4 年了。知道会话 id 算法是否从那时起即兴创作会很有趣......
    • @ColinM:这些网站每天有 100 万独立访问者。
    • Aparantly 它当前基于(MD5/SHA1 哈希)用户的远程地址、当地时间和一些random number (LCG)
    • 我不需要破坏手机,手机会不断地破坏自己。 :)
    【解决方案6】:

    session_id 的大小
    假设 seesion_id 是均匀分布的,并且 size=128 位。假设地球上的每个人每天登录一次,并且持续 1000 年的新会话。

    num_sesion_ids  = 1000*365.25 *7*10**9 < 2**36
    collission_prob < 1 - (1-1/2**82)**(2**36)  ≈ 1 - e**-(1/2**46) 
                    ≈ 1/2**46 
    

    因此发生一次或多次碰撞的概率小于 7 亿分之一。因此 128 位的 session_id 应该足够大。正如在其他 cmets 中提到的,session_manager 也可能会检查新的 session_id 是否已经存在。

    随机性
    因此,我认为最大的问题是 session_id:s 是否以良好的伪随机性生成。关于这一点,您永远无法确定,但我建议为此目的使用众所周知且经常使用的标准解决方案(您可能已经这样做了)。

    即使通过检查避免了冲突,session_id的随机性和大小也很重要,这样黑客就无法以某种方式进行有条件的猜测并以很大的概率找到活跃的session_id。

    【讨论】:

    • 我不是数学家,但我认为您忘记了Birthday problem,因此碰撞的可能性仍然很小,比您建议的要大得多。此外,正如 djsadinoff 所建议的那样,PHP 不一定使用默认生成随机数的好方法。
    • 实际上估计不成立。上面的计算是一个简化的估计,我们估计 session_id nr i 的冲突概率是 = 1/282(尽管 =typo 应该是 1/292)。实际上,只要之前没有发生碰撞,概率就是 (i-1)/2128。 1/292 只保留最后一个 session_id。
    【解决方案7】:

    如果您想了解 PHP 默认如何生成会话 ID,请查看 Github 上的源代码。它当然不是随机的,而是基于这些成分的散列(默认值:md5)(参见代码 sn-p 的第 310 行):

    1. 客户端的IP地址
    2. 当前时间
    3. PHP 线性同余生成器 - 伪随机数生成器 (PRNG)
    4. 操作系统特定的随机源 - 如果操作系统有可用的随机源(例如 /dev/urandom)

    如果操作系统有可用的随机源,则生成的 ID 作为会话 ID 的强度很高(/dev/urandom 和其他操作系统随机源(通常)是加密安全的 PRNG)。但是,如果它没有,那么它是令人满意的。

    生成会话标识的目标是:

    1. 尽量减少生成两个具有相同值的会话 ID 的概率
    2. 在计算上生成随机密钥并点击正在使用的密钥变得非常具有挑战性

    这是通过 PHP 的会话生成方法实现的。

    你不能绝对保证唯一性,但是两次命中同一个哈希的概率是如此之低,一般来说,不值得担心。

    【讨论】:

      【解决方案8】:
      <?php
      session_start();
      $_SESSION['username']="username";
      ?>
      
      <!DOCTYPE html>
      <html>
      <head>
          <title>Update</title>
      </head>
      <body>
      
      <table border="2">
          <tr>
              <th>Username</th>
              <th>Email</th>
              <th>Edit</th>
          </tr>
      <?php
           $conn=mysqli_connect("localhost","root","","telephasic");
           $q2="select * from register where username = '".$_SESSION['username']."'";
           $run=mysqli_query($conn, $q2);
           while($row=mysqli_fetch_array($run))
           {
               $name=$row[1];
               $email=$row[2];
           ?>
      
          <tr>
              <td><?php echo $name; ?></td>
              <td><?php echo $email; ?></td>
              <td><a href="edit.php"> Edit </a></td>
          </tr>
       <?php } ?>
       </table> 
       </body>
      

      如果您的用户名不同或唯一,您可以使用此代码进行会话

      【讨论】:

        【解决方案9】:

        您可以选择将各种会话与数据库生成唯一字段一起存储在数据库中;将两者合并并将其保存在会话变量中,然后检查该变量而不是会话 ID。

        【讨论】:

        • 欢迎来到stackoverflow。不幸的是,您的回答并没有试图回答这个问题。 OP 询问会话 ID 的唯一性。将数据存储在数据库中,然后使用会话变量来检索它只会增加问题的复杂性,不是吗?
        • @NoahBoegli 其他解决方案建议使用更复杂的方法。
        【解决方案10】:

        我知道这篇文章很老了。然而,我在这里添加我的答案,因为我找不到这个问题的相关解决方案,即使在我自己发布了一个类似的问题之后。然而,我从对我的帖子的回复中得到了线索。对于那些对算法和解决方案感兴趣的人,here 进行了解释。它使用会话和不同 cookie 的组合。

        简单的算法是这样的

        会话处理将通过使用 DB 的自定义类“MySessionHandler”完成

        1.就在 session_start 之前,cookie cookie_start_time 被设置为当前时间。此 cookie 的生命周期将与会话的生命周期相同。两者都使用变量 $this->cookieLifeTime 来设置生命周期。

        1. 在会话“_write”中,我们将该值设置为 db 表字段 cookie_start_time 与 $this->cookieStartTime 相同

        2. 在会话“_read”中我们进行检查

        if($getRowsOfSession[0]['cookie_start_time'] != $this->cookieStartTime).

        如果返回 true,则表示这是一个重复会话,用户被重定向以销毁会话并再次重定向以启动新会话。(总共 2 次重定向)

        【讨论】:

        • 请将链接的相关部分贴在答案中。
        猜你喜欢
        • 2011-07-29
        • 1970-01-01
        • 2014-08-09
        • 2010-10-23
        • 2015-01-12
        • 2012-06-24
        • 1970-01-01
        • 1970-01-01
        • 2011-01-15
        相关资源
        最近更新 更多