5

I'm gonna start by saying it: I'm merely a cybersecurity enthusiast, not an expert. Thus, I'm gonna state what I think I know so far, please feel free to correct me at any time.

Through my readings, I've come to learn about:

  • The existence of CSRF
  • The basics behind it, for both GET and POST requests
  • Token and Referer mitigation techniques
  • How the Token can be retrieved if the target website hosts an XSS vulnerability
  • The fact that the referer is passed in clear text through HTTP headers and could thus be spoofed
  • cURL used to load the page first, get the token, and use this one to send the POST data and get page post-auth contents

Hence, my question is the following: if someone uses a PHP script that loads the page hosting the POST form, gets the randomly generated token, and sends the POST data with a custom "Referer" header matching the destination website, is there anything I can do on my server to mitigate this?

Anders
  • 64,406
  • 24
  • 178
  • 215
MadWard
  • 233
  • 2
  • 11

2 Answers2

4

I think you are misunderstanding how an CSRF-attack works, and why CSRF-tokens protects against them. So lets begin with how one works.

The attacker fools the victim to visit http://evil.com that contains a form that automatically does a POST to http://bank.com/transfer?to=evilHacker&amount=1000000. If the victim is already logged in to her bank, the cookie with the session ID will be sent like usual by the browser and there is no way for the bank server to know that the victim did not actually intend to transfer the money. Note that this relies on the browser sending the cookie with the session ID to bank.com.

So how can a CSRF-token help? If the bank.com always checks that a random token unique to that session is present in the request, evil.com can not forge the request since the evil hacker running that site does not know what the token is.

The referer check works in a similar way. The request made by the browser from the site evil.com would have evil.com and not bank.com as the referer. Browsers do not allow modification of the referer header, so the attacker can't forge that.

So what about your line of attack - having the attacker request the site with a PHP script on her server to get the CSRF-token? This will not work, because the attacker will not get the victims CSRF-token. The token is unique to the session, and hence the cookie with the session ID. But the attackers does not know what session ID the victim has, so she can not include it in the request.

Notice the difference to the first scenario, where the browser included the cookie. That can not happend on the server.

Anders
  • 64,406
  • 24
  • 178
  • 215
  • 1
    You're right, I had my mind jumbled for a while. I do understand how an CSRF-attack works, but I foolishly overlooked the fact the PHP script is executed server-side, and thus has almost nothing to do with the client's browser. My bad, and thank you ! – MadWard May 23 '16 at 15:57
1

Anders answer addresses the question, but only offers the solution of storing a copy of the token in the session. It would also be possible to store the token client side as long as it is appropriately protected against replay attacks - but this has significant overlap with the problem of session hijacking....

if ($_REQUEST['token']) {
   if (validate($_REQUEST['token'], $_COOKIE['ctoken'])) {
     // do the protected thing....
   } else {
     // handle exception
   }
}
$token=sha1(openssl_random_pseudo_bytes(40)) . ":" . time();
$client_stored_token=encrypt($token, create_key);
set_cookie('ctoken',$client_stored_token);

function validate($token, $client_stored_token) 
{
    $client_token=decrypt($client_stored_token, create_key());
    @list($rand_bytes, $timestamp)=explode(':', $client_token);
    if ($rand_bytes==$token && time()-$timestamp<MAX_THRESHOLD) {
       return true;
    } 
    return false;
}
function create_key()
{
   return sha1($_SERVER['HTTP_USER_AGENT'] 
      .(int)(ip2long($_SERVER['REMOTE_ADDR'])/65536)
      .SOME_STATIC_SALT);
}

(it may also be possible to propagate the token via the window.name but that needs some more thought).

Anders noted that:

Browsers do not allow modification of the referer header, so the attacker can't forge that.

Unfortunately there are a whole lot of issues with the referer header in various browsers - you'll come unstuck if you rely on that.

The fact that the referer is passed in clear text through HTTP headers and could thus be spoofed

Even the most sophisticated CSRF and session protection mechanisms are easily defeated by a MITM on an HTTP connection. That's why we use HTTPS.

symcbean
  • 18,278
  • 39
  • 73