【问题标题】:What is PHP's session.referer_check protecting me from?PHP 的 session.referer_check 是什么保护我的?
【发布时间】:2011-06-19 08:02:12
【问题描述】:

我正在使用 CakePHP 制作一个需要相当安全的系统,因为我们正在处理金钱、客户的帐户等。到目前为止,一切都运行良好,直到我不得不与一个支付平台集成我需要重定向到他们的网站,然后他们重定向回我的网站。

这在我的开发机器(调试 = 2)中运行良好,但在生产中,当客户被重定向回来时,他会收到登录提示,而不是回到他的“登录区域”。经过大量挖掘,我发现这是因为 CakePHP 设置了 session.referer_check,如果 HTTP_REFERER 来自我以外的其他主机,这会使会话无效。

现在,通常情况下,我会毫不犹豫地禁用它,但在这个系统中,我比平时更关心安全性。

我的问题是 session.referer_check 究竟应该保护我免受什么影响?
如果我关闭它,会对我的网站进行什么样的攻击/利用/坏事?

我猜这肯定是有原因的,但我无法想象它会保护我免受什么伤害。

你能给我一些想法吗?
禁用它是否安全?

谢谢
丹尼尔

【问题讨论】:

  • 您是否 100% 是在检查引荐来源网址,而不是在先前请求中与表单一起发送的令牌以防止 CSRF?
  • 100% 确定。 CakePHP 没有检查引荐来源网址,它只是打开了referer_check(检查引荐来源网址本身的 PHP 功能:php.net/manual/en/…) - 另外,我看到的结果是让人们注销。当 CakePHP 不喜欢它获得的 CSRF 令牌(或者当它没有获得)时,CakePHP 所做的就是“黑洞”(基本上是空白页面)

标签: php security cakephp


【解决方案1】:

这是为Session Fixation 和 CSRF/XSRF 提供有限的保护。检查推荐人是a valid method of stopping xsrf。停止会话固定的更好方法是 Session.use_only_cookies,因为黑客无法在受害者浏览器上为他尚未控制的域设置 cookie。

但是,Session.referer_check 很容易绕过。它只是在引用域中寻找子字符串。如果子字符串一起丢失,如果原始 url 是 https:// 则发生这种情况,则会话 ID 将无效。但是,因为它是子字符串而不是完整字符串,所以您可以通过引用 www.somedomain.com.some_hacker.com 来绕过 www.somedomain.com。所以简而言之,我认为这是完全没用。

【讨论】:

    【解决方案2】:

    请记住,基本上所有 referer_check 所做的都是这样的:

    $pattern = "/^http:\/\/www\.myurl\.com(\/.*)*$/";
    
    if(!empty($_SERVER['HTTP_REFERER']) && !preg_match($pattern, $_SERVER['HTTP_REFERER'])) {
       session_destroy();
    }
    

    referer_check 中内置的 PHP 不接受 URL 数组,这很烦人,但您可以随时创建自己的。

    因此对于 CakePHP,您可以执行以下操作:

    // ADD THIS TO /app/config/config.php
    $config['CustomSecurity'] = array(
        'accept_referers' => array(
            'http://www.my_site.com',
            'https://www.other_allowed_referer.com',
        )
    );
    
    // ADD THIS TO /app/app_controller.php
    
    private function referer_check(){
       if(!empty($_SERVER['HTTP_REFERER'])) {
          $accept_referers = Configure::read('CustomSecurity.accept_referers');
          $referer_accepted = false;
          foreach($accept_referers as $referer) {
             $pattern =  '/^'.preg_replace('/(\.|\/)/','\\\$1',$referer).'(\/.*)*$/';
             if(preg_match($pattern, $_SERVER['HTTP_REFERER'])) 
                $referer_accepted = true;
          }
          if(!$referer_accepted) {
             $this->Session->destroy();
             exit;
          }
       }        
    }
    

    在您的app_controller::before_filter 函数中,致电:

    $this->referer_check();
    

    ...或者类似的东西...对不起代码格式,textarea是一个tard :)

    【讨论】:

      【解决方案3】:

      以这种方式检查引用可以帮助防止Cross-site request forgery。

      理想情况下,您需要一种方法来让引用者检查匹配您自己的域或支付平台的域,但由于它是简单的子字符串检查而不是模式匹配,我认为这是不可能的.

      如果您禁用此功能,您应该采取其他措施来防止此类攻击。

      【讨论】:

      • 引用者检查可以被欺骗。随机数或一次性令牌是防止 CSRF 的标准。
      • 我也这么认为。现在,在我的站点中,您无法使用 GET 更改 任何内容,只能使用 POST,关闭浏览器后站点不会记住您,并且 CakePHP 已经生成“魔术令牌”以避免XSRF 表单 POST。考虑到所有这些,我可以安全地禁用它吗?
      • @gravelpot:标头可以被攻击者欺骗,但这不是 CSRF 的目的,它是关于让用户的浏览器自己执行从另一个(恶意)站点到您的(好)站点的请求。在这种情况下,您不能欺骗推荐人。 (而且我正在使用令牌,我网站上的所有内容都在不“记住你”的登录墙后面)
      • 鉴于您所描述的,我想说您可以安全地禁用此功能,但我不是安全专家。使用其他技术以及引用者检查来防止 XSRF 的原因是 1)某些用户/代理可能会保留引用者信息,而您不想阻止他们使用您的应用程序 2)浏览器中可能存在错误或如 Wikipedia 文章中所述,允许欺骗引用者的插件(这种情况很少见)。
      • @gravelpot 你错了。在 CSRF 攻击中欺骗referer 是不可能的。
      猜你喜欢
      • 2013-01-25
      • 2014-07-28
      • 2018-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-01
      • 2020-09-26
      • 1970-01-01
      相关资源
      最近更新 更多