1

I have a yii (php) project and now I want to test, if it is safe against csrf attacks.

The code looks like this:

if (!Yii::app()->request->isAjaxRequest)){
   die("error");
} else { 
   // Do stuff
}

Now, if I call the URL in Firebug, It works ("Do stuff" is executed).

$.get("example.com/foo", function(data){
    // Works - no error
});

But, if I call the exact same URL in my Browser, I get "error", since Yii::app()->request->isAjaxRequest will be false.

Does that mean, my application is safe against CSRF attacks or is there any way to trick the "Yii::app()->request->isAjaxRequest" into thinking its an real Ajax-Request?

Thank you very much!

Tream
  • 1,049
  • 2
  • 13
  • 29

2 Answers2

2

Short answer: you've misunderstood what CSRF is about.

Long answer: CSRF is about protecting POST requests, including the ones made by AJAX. It's done by creating a randomly generated token to be rendered on a page as a hidden form field, which adds it to the request so it can be verified before rest of the form gets processed. If you're making an AJAX POST call you need to add the CSRF token to the request manually. When the CSRF token is missing in a POST request, the framework throws an exception.

The isAjaxRequest property just checkes for specific http header. You should not rely on it, that is it should not be used to secure access.

Jan Waś
  • 81
  • 4
  • Thank you for your reply. A CSRF attack can be performed with a normal GET too, if the application changes data on GET. Is there any attack vector for the example I posted? If I put the url (for example) inside of an tag and send it to a logged in user, I´ll get the "error". Is there a way to bypass this check? - Thank you!! – Tream May 20 '15 at 22:42
  • You should avoid using GET to modify anything, that's the whole point. Otherwise, you should also require the CSRF token for those requests. To answer your question, you'd have to modify the request headers. That requires some tools. Check out the AJAX request in your browsers console to see how the header looks like now. – Jan Waś May 21 '15 at 05:36
1

The code for isAjaxRequest is as follows:

public function getIsAjaxRequest()
{
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH']==='XMLHttpRequest';
}

It appears to be checking that the X-Requested-With HTTP header is set. This is actually a valid defence for CSRF because it is a header that cannot be sent cross-domain, without the consent of CORS. Yes, an attacker with cURL can spoof an AJAX request by setting this header, but it would do them no good in an CSRF attack as they do not have the user's cookies to send with it.

The only drawback with this method is that you can only use it to protect AJAX requests from CSRF, not normal web form POSTs, as you cannot set headers using this mechanism.

If you need to protect web form POSTs then you need to implement a solution such as the Synchronizer Token Pattern. This is where you generate a cryptographically secure token server side and associate it with the user's session. You then check this key on each form POST, as you include it in a hidden form field. This prevents CSRF because an attacker cannot read the token from the page.

Community
  • 1
  • 1
SilverlightFox
  • 32,436
  • 11
  • 76
  • 145