6

I'm using anti-CSRF tokens on all my forms to prevent CSRF attacks. Also, the tokens are being saved in the $_COOKIE variable to validate against the value I get from the form. I'm resetting the token each time a form is loaded.

But there are a few forms that are using $.post, i.e. AJAX to submit and getting a JSON response.

The $_COOKIE variable is not set because of AJAX being used.

Is there a workaround or am I doing something wrong?

EDIT: Adding client-side and server-side code sample

Client-side:

<?php
$tokenVal = md5(uniqid(mt_rand(), true));
setcookie ("token", $tokenVal);
?>
<form action="target.php" method="post" name="abc">
<input type="text" name="city" id="city" value="abc" size="25" maxlength="10">
<input type="hidden" name="csrf" value="<?php echo $tokenVal; ?>">
<a class="cssButton buttonColor right" id="billToSubmit">Save</a>
</form>

Server-side:

if($_POST['csrf'] == $_COOKIE['token']) {
//process further
} else {
die("Invalid form source")
}

The form is being submitted using $.post. The problem I'm facing is that $_POST['csrf'] is never equal to $_COOKIE['token']!

2
  • 1
    What kind of data do you send with your XHR request via $.post?
    – Gumbo
    Commented Sep 11, 2012 at 5:35
  • @Gumbo I send simple form data. I'm simply serializing the form. Commented Sep 11, 2012 at 13:28

4 Answers 4

2

Assuming the CSRF token is available to JavaScript, you can use setRequestHeader to attach the request token manually and modify your server to look for the request token in the cookie header, or for requests that should be accessible via XHR in the header you supply.

2
  • Yes, but you cannot set the cookie header in a CSRF attack.
    – rook
    Commented Sep 11, 2012 at 18:04
  • @Rook, of course you're right. I'm an idiot. You want the token to be scoped to the request and not any requests that happen to be initiated by other frames during the lifetime of the cookie. Fixed. Commented Sep 12, 2012 at 0:00
1

Most Javascript frameworks add a specific header when POSTing requests, such as X-Requested-With: AJAX. In theory, on the backend you could check for the existence of this header to be sure that your form was submitted via AJAX (an attacker should not be able to make a third party add a custom header to a form submission). Since AJAX requests can only come from the same domain, you should be safe from CSRF attacks.

But it has been discovered that in the presence of some combinations of browser plugins it is actually possible for attacker to craft a request with custom headers. This makes the above approach not so sound. Today the preferred protection is to pass the CSRF token to the client even for AJAX submissions. For instance you can still add it into a hidden field and then read it with javascript.

EDIT: With regards to the $_COOKIE$ variable not being set in AJAX requests, I do not understand your point. You can actually set cookies in AJAX requests, and even normal cookies will be preserved, provided they are not http-only.

4
  • I'm actually setting the cookie value in PHP and then adding the same value to the hidden field. But when I check on server side when the form is submitted, the $_COOKIE value does not match the token value I get in the hidden form field. Commented Sep 11, 2012 at 15:12
  • I still do not understand. Are you saving the content of the token server-side somewhere, or are you simply relying on two different data both coming frmo the client? In the second case, I do not see how this achieves CSRF protection
    – Andrea
    Commented Sep 11, 2012 at 16:08
  • I'm comparing the $_COOKIE['token'] value with the hidden form field value. I assume that's how the "Double Submit Cookies" way works. Commented Sep 11, 2012 at 17:00
  • If I understand correctly, if an attacker is able to make a user submit a form with a given token both as a hidden field and as a cookie, whatever the token, he will be able to attack your site. Since, as I mention in my answer, with some browser plugins it is possible to induce other people to send requests with custom headers - and thus cookies - your approach seems to me as safe as checking the X-Http-Requested-With header. It will work for the majority of users but it is not completely secure. You must keep track of the actual value of the token server-side
    – Andrea
    Commented Sep 11, 2012 at 20:44
0

This is a valid form of CSRF protection because the attacker will not know the value of the cookie there for the attacker will not have a valid value for the token post variable. This method does not require a per-user state which is a benefit.

The CSRF Prevention Cheat Sheet is a good resource.

5
  • And what about the XHR request via $.post?
    – Gumbo
    Commented Sep 11, 2012 at 5:16
  • @Gumbo By the nature of AJAX requests, the domain of origin will need to have access to the token value in order to build valid requests. However, JavaScript originating from another domain should never be allowed access to this variable. An attacker can obtain the cookie value and the CSRF token with XSS, but this is always true for token based CSRF protection, HTTPOnly cookies doesn't help.
    – rook
    Commented Sep 11, 2012 at 5:50
  • It seems to me that the XHR requests do not have a token at all. That’s the reason for my question as you seem to be missing that.
    – Gumbo
    Commented Sep 11, 2012 at 17:05
  • @Gumbo hmm i think both the OP and my post are explaining the same security measure. However, I can see how this measure is confusing.
    – rook
    Commented Sep 11, 2012 at 18:03
  • Ah, never mind. I just forgot for one second that XHR does already send any existing cookies along.
    – Gumbo
    Commented Sep 16, 2012 at 6:39
-1

If you are using cookies to store (and retrieve) the CSRF token, that doesn't really mitigate the CSRF vulnerability. Correction: As clarified in comments, this line isn't true for the way Gaurav is using CSRF tokens.

Instead of making your own CSRF prevention scheme, why not use something like PHP CSRF Guard

4
  • 2
    I'm also adding the token value as a hidden field in the forms being submitted. Also, I can't use sessions because of the application architecture. I think what I'm doing is the "Double Submit Cookies" way of preventing a CSRF attack. Commented Sep 10, 2012 at 21:32
  • @Shivam The attacker won't know the value of the cookie, if this cookie value is verified against the value in the form, then this is a valid method of CSRF protection. The owasp page doesn't disagree with this.
    – rook
    Commented Sep 10, 2012 at 21:58
  • 1
    Yeah, you are right. I misinterpreted the question. My bad. Gaurav, in case you are not able to send cookies in AJAX requests, one way out could be to have the token appended in the querystring of the URL, eg: example.com/createuser.php?token=<token> The script createuser.php will then compare the $_GET['token'] and $_POST['token_hidden_form_field'] and proceed if they match. In this scheme, if a attacker manages to POST a form, he'd still need to know the correct querystring parameter 'token'. Commented Sep 10, 2012 at 22:22
  • @Shivam I was under the impression that adding the token value to the query string is a bad idea. This opens your site up to replay attacks, etc. Commented Sep 11, 2012 at 15:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .