【问题标题】:PHP Sessions + Useragent with saltPHP Sessions + 用户代理加盐
【发布时间】:2009-03-05 20:49:26
【问题描述】:

最近几天我一直在想它,但我读了一些关于如何使您的 PHP 会话更安全的文章。几乎所有这些文章都说您需要在会话中使用额外的盐保存用户代理。像这样的:

$fingerprint = md5('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT']);

盐会使攻击者更难劫持或任何会话。但是为什么每次检查时都要加盐:

md5('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT']) == $_SESSION [ 'fingerprint' ]

既然攻击者仍然只需要用户代理(相对而言是一小组不同的用户代理)和 sessionid,为什么加盐会使它更安全?

可能是我忽略了一些小事,但无法弄清楚,让我发疯了哈哈

谢谢!

【问题讨论】:

    标签: php user-agent salt session-hijacking


    【解决方案1】:

    建议添加盐的原因很简单。一般来说,当你创建这个“指纹”时——如果你只使用一个数据项,它的数据集有限,那么外部黑客就更容易生成这个指纹,并劫持会话。

    在上面的示例中,是的,如果攻击者同时拥有“指纹”和用户代理,那么他们将能够劫持会话。

    添加盐只会使攻击者更难生成指纹,这是“如果他们只有一条信息,那么最后一条信息将变得无用)的情况

    我建议您添加更多内容,例如,在 vBulletin(我曾经从事的一个项目)中,使用以下代码生成会话 ID 哈希(与指纹基本相同)。

    define('SESSION_IDHASH', md5($_SERVER['HTTP_USER_AGENT'] . $this->fetch_substr_ip($registry->alt_ip))); // this should *never* change during a session
    

    另外,会话哈希是使用

    生成的
    md5(uniqid(microtime(), true));
    

    这些都在尝试识别会话时被检查

    因此,要劫持会话,此人需要知道以下内容

    • 创建会话时服务器上的时间(准确)
    • 用户浏览器代理字符串
    • 用户的 IP 地址

    他们还必须欺骗 IP 地址(或至少前 2/3 个八位字节)才能做到这一点。

    如果他们实际上已经设法获得了上述信息,那么他们很可能能够以其他方式进行攻击,而不仅仅是会话劫持。

    vBulletin 实际上并没有使用“盐”本身,但是,在你上面的例子中,盐只是增加了有限的熵,最好找到尽可能多的熵。

    例如,在我目前用 python 编写的东西中,我生成了一个散列以用于 XSRF 保护。以下是我使用的。

        self.key = sha1(
            self.user.username +
            self.user.password +
            settings.SECRET_KEY +
            strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime())
        ).hexdigest()
    

    它需要用户的用户名和密码、当前时间和预设的盐来生成它。由于盐和时间,这对于攻击者来说很难生成(不过,请注意,这只是因为一旦使用它就会改变,随着时间的推移,某人不需要太多时间来如果它没有改变,则为特定用户破解它)

    【讨论】:

    • 加盐哈希只是默默无闻,实际上并没有增加攻击的难度。如果你正在编写一个开源应用程序,这会加倍。
    【解决方案2】:

    如果我理解正确,您想防止猜测会话 ID 的远程攻击者劫持会话?

    如果不是这种情况,那么您就严重超出了您的深度 - 可以窥探流量的攻击者也可以模仿用户代理,而获得会话存储访问权限的攻击者无论如何都可以控制您。

    如果您存储用户代理字符串以将会话“锁定”到当前用户代理,那么散列它实际上没有意义 - 完整用户代理字符串的字符串比较更快(然后散列然后比较)并且在存储方面并没有显着增加。

    我不相信存储用户代理能提供足够的差异化——更好的办法是在会话开始时生成一个更大的 ID(更多位)(也许 sha1 当前时间戳 + 用户名 + 用户代理 + 一些东西),然后将其存储在 cookie 以及会话中,并在每个附加请求中匹配它。这不会改变攻击向量(你仍然需要猜测一些数字),但是通过大幅增加攻击的难度,很容易显着增加成功攻击必须猜测的位数。

    更新:

    其他答案顺便提到的但对于加盐哈希很重要的一点:如果您希望攻击者访问您存储的哈希而不是您的代码,然后以某种方式使用它利用攻击。

    这对于长期存储的密码很有意义,通常在众所周知的位置,并且被难以定位的代码使用。

    这对您的用例没有意义,因为:

    1. 该信息仅在会话进行中(超时之前)才有效,这很少超过几个小时,之后 - 即使他们获得了存储并解码了所有内容 - 会话也无法被劫持,因为它已经结束。
    2. 通常,如果攻击者能够及时访问您的会话存储,他们就可以访问您的纯文本 PHP 代码并且可以看到您的 salt。
    3. 除非您将会话存储在完全不合理的位置(例如 S3 存储桶),否则与许多其他更有用的攻击相比,哈希窃取攻击的可能性要小得多。

    简而言之:不要浪费时间编写会话验证代码——PHP 内置的会话管理已经足够安全了。

    【讨论】:

      【解决方案3】:

      如果您在自己的服务器上,加密会话变量是没有意义的,因为它们不会离开服务器。请参阅 Linead 回复What do I need to store in the php session when user logged in? 了解更多信息。如果您在共享服务器中,您可能需要加密除会话 ID 之外的每个会话变量,因为它们存储在所有邻居正在使用的同一 Web 服务器可以读取的临时文件中。

      无论如何,如果你真的担心安全问题,你最好使用自己的(虚拟或非虚拟)服务器,这样危险只会来自你的服务器之外。

      一些会话风险示例:

      • 您的服务器在 URL 中发送会话 ID,您的用户点击 badguys.com 的链接他们将在服务器变量中获取引用者(完整的 URL,包括您的会话 ID)、浏览器和您用户的 IP 地址.如果您不检查 IP,或者您的用户使用开放式代理,他们只需安装相同的浏览器版本,粘贴 URL,即可完成。
      • 用户转到公共 PC,登录,然后离开而不关闭他的会话(嘿,他毕竟是人类)。行中的下一个人打开浏览器,检查历史记录并找到一个打开的会话。糟糕。

      所以,按照我通常的偏好,你可以采取一些措施:

      1. 不要在 URL 中发送会话 ID;在 PHP 中启用 session.use_only_cookies。缺点:用户需要启用 cookie。
        • 在进行危险操作(更改密码、下订单...)时,再次询问用户密码。您也可以定期进行。缺点:烦人。
        • 超时会话快。缺点:在大多数网站中,这会迫使用户经常登录,这让他们很恼火。
        • 使用 SSL(避免“中间人”攻击的唯一方法)。缺点:慢。愚蠢的浏览器消息。服务器上需要 SSL。
        • 检查 IP。缺点:对使用公共代理的访问者无效。烦人的动态 IP。
        • 检查用户代理(浏览器)。缺点:几乎没用,UA 很容易获得且难以模仿。

      (我理所当然地认为您已经为最大安全性配置了 PHP)。

      一些更极端的措施:

      • 保持服务器和浏览器之间的永久连接,例如使用 Java 小程序。没有连接,没有会话。缺点:用户需要 Java、ActiveX 或任何你使用的东西。会话通过浏览器关闭(这可能很好)。不适用于非常慢的连接。服务器负载较高。你需要打开端口,有一个专门的小程序服务器。
      • 相同,但使用异步请求(例如 AJAX)非常频繁地刷新会话,并且超时时间很短。或刷新隐藏的 IFRAME。缺点:用户需要 JavaScript。不适用于非常慢的连接。服务器负载更高。
      • 相同,但重新加载整个页面。缺点:用户需要 JavaScript。阅读页面时自动重新加载非常烦人。

      在某些极端情况下,您可以忘记会话并改用 Apache 身份验证。最简单的解决方案,但有很多限制。

      【讨论】:

        【解决方案4】:

        由于指纹存储在服务器端,因此您无需使用加盐哈希。 “正常”的散列足以减少数据。

        【讨论】:

        • 盐没用,看我的cmets给你答案。
        • 当然,加盐哈希比普通哈希好。但在这种情况下,它是无关紧要的,因为数据存储在会话中。并且无法获得该数据(通常)。所以没有区别。
        【解决方案5】:

        我看到了给你的指纹加盐的一个目的。如果一个坏人掌握了您的会话数据库(天知道为什么)但没有掌握您的代码,他无法通过尝试常见的用户代理来“猜测”您的指纹识别方法。

        【讨论】:

        • 值得注意的是,无论如何您都不应信任任何人 - 比如说,您经营一家企业并雇用了错误的人来对您的服务器进行某事 - 根据他们在那里可以访问的内容,他们可以随意窃取会话。
        【解决方案6】:

        我也对partially protect from session impersonation attacks 这样做。您还需要包含 IP 地址。

        请记住,当客户端的浏览器自动更新用户代理时,您会认为他的会话已被劫持;)

        【讨论】:

        • 在会话指纹中包含 IP 地址是不好的,因为它会阻止用户合法更改 IP 地址,例如断开连接的 DSL 线路
        • @Guss:当这种情况发生时(或当用户代理的浏览器自动更新时),我会使会话无效。没什么大不了的,用户必须重新登录。
        【解决方案7】:

        请记住,如果您这样做,您会在用户升级浏览器时强制他们重新登录。这没关系,但请确保这是您的意图。

        使用用户的远程地址也不是没有问题。许多人从不同的位置使用同一台计算机。移动设备,在家和工作中使用的笔记本电脑,在 Wifi 热点使用的笔记本电脑等等。恕我直言,以新 IP 地址需要登录的方式使用 IP 地址是一个坏主意,除非您正在处理高度敏感的信息,例如网上银行。是这样吗?

        你担心什么?外部攻击?或者在有人可以读取您的会话信息的共享主机情况下?

        如果是后者,解决方案很简单:只是不要在会话中存储任何敏感内容。任何敏感的东西都应该存储在数据库中。

        就创建秘密盐而言,您需要使用不可猜测的东西。我会选择在创建用户时创建的随机字符串之类的东西。如有必要,每次会话无效时重新创建它。

        至于什么会让它更安全,你自己说过:用户代理字符串是有限的(不到一百个可能会覆盖 99.99% 的用户)。盐只是增加了可能性的数量。话虽如此,如果您在所有会话中都使用相同的盐,那么用蛮力发现它只是时间问题。

        【讨论】:

          【解决方案8】:

          好的,例如我正在使用以下虚构代码:

          <?php
          
          // The sessionid cookie is now a certain hash
          if ( array_key_exists ( $_COOKIE [ 'sessionid' ] ) )
          {
              // Get the session from database
              $db_sessid = $pdo -> getStuff ( 'session_database', $_COOKIE [ 'sessionid' ] );
          
              if ( $db_sessid !== null && $db_sessid [ 'fingerprint' ] == sha1 ( 'SOMESALT' . $_SERVER [ 'HTTP_USER_AGENT' ] ) )
              {
                  set_cookie ( ... ); // New sessionid and write also to DB
          
                  // User is now logged in, execute some user stuff
              }
              else
              {
                  // Session doesn't exist, or the fingerprint does not match
              }
          }
          

          现在攻击者只需要 sessionid,它位于 cookie(随 HTTP 标头发送)和用户代理中。那么添加盐还有什么意义呢?

          在我看来,检查 IP 也不是一个好的选择,一些提供商或代理会在每次请求时更改它们。

          到目前为止感谢(-:

          【讨论】:

          • 加盐哈希在这种情况下没有安全优势。
          • 那我怎样才能让它受益呢?因为几乎每篇文章都在说它很重要,但没有解释为什么/如何使它好用..
          【解决方案9】:

          在满足所有安全参数后,您允许 cookie 设置一个 cookie,如果参数不满足,则 cokkie 将永远不会设置为 nice,但如果 cookie 有一个可见的参数,那么会发生什么。同样,如果条件从未满足,则会议将不会被满足。这就是你真正想要的。记住检查满足条件通过 cookie 提供会话和查看数据方式 记住 cokkie 坐在客户的浏览器上 关于stelios

          【讨论】:

            猜你喜欢
            • 2015-08-06
            • 1970-01-01
            • 2014-05-03
            • 2012-07-22
            • 2018-11-09
            • 2013-09-22
            • 2014-04-22
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多