Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is PHP's session.referer_check protecting me from?

I'm making a system with CakePHP that needs to be decently secure, because we're dealing with money, customer's accounts, etc. So far everything's been working great, until I've had to integrate with a payments platform in which I need to redirect to their site and they redirect back to mine.

This works fine in my dev machine (debug = 2), but in production, when the customer is redirected back, he gets a login prompt instead of landing back in his "logged in area". After much digging I found this is because CakePHP sets session.referer_check, which invalidates sessions if the HTTP_REFERER comes from another host than mine.

Now, normally, i'd disable this without a second thought, but in this system i'm a bit more concerned about security than normal.

My question is what exactly is session.referer_check supposed to protect me from?
What kind of attack/exploit/bad thing can be done to my site if I turn it off?

I'm guessing that there's gotta be some reason why this exists, but I can't imagine what it'd protect me from.

Could you give me any ideas?
Is it safe disabling this?

Thank you
Daniel

like image 421
Daniel Magliola Avatar asked Feb 01 '11 14:02

Daniel Magliola


3 Answers

This is to provide limited protection for Session Fixation and CSRF/XSRF. Checking the referer is a valid method of stopping xsrf. A better method of stopping session fixation is Session.use_only_cookies, because a hacker cannot set a cookie on a victims browser for a domain he doesn't already control.

However, Session.referer_check is easy to bypass. Its just looking for a substring in the referer domain. If the substring is missing all together, which happens if the originating url is https:// then the session id will be invalid. However, becuase its a substring and not a full string then you could bypass this for www.somedomain.com by refering from www.somedomain.com.some_hacker.com. So in short, I think this is completely useless.

like image 127
rook Avatar answered Nov 15 '22 05:11

rook


Bear in mind that basically all the referer_check is doing is something like:

$pattern = "/^http:\/\/www\.myurl\.com(\/.*)*$/";

if(!empty($_SERVER['HTTP_REFERER']) && !preg_match($pattern, $_SERVER['HTTP_REFERER'])) {
   session_destroy();
}

It is annoying that PHPs built in referer_check won't accept an array of URLs, but you can always make your own one that does.

So for CakePHP, you could do something like the following:

// 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;
      }
   }        
}

AND IN YOUR app_controller::before_filter FUNCTION, CALL:

$this->referer_check();

... or something like that anyway ... sorry about the code formatting, the textarea was being a tard :)

like image 39
James Avatar answered Nov 15 '22 05:11

James


Checking the referer in this way can help protect against Cross-site request forgery.

Ideally you'd want a way to have the referer check match either your own domain or the domain of the payment platform, but as it is a simple substring check rather than a pattern match I don't think this would be possible.

If you disabled this you should put other measures in place to protect against such attacks.

like image 3
mikej Avatar answered Nov 15 '22 06:11

mikej