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']!

Gaurav Sharma
  • 161
  • 1
  • 5

4 Answers4

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.

Mike Samuel
  • 3,873
  • 17
  • 25
  • Yes, but you cannot set the cookie header in a CSRF attack. – rook Sep 11 '12 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. – Mike Samuel Sep 12 '12 at 00: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.

Andrea
  • 381
  • 2
  • 5
  • 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. – Gaurav Sharma Sep 11 '12 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 Sep 11 '12 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. – Gaurav Sharma Sep 11 '12 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 Sep 11 '12 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.

rook
  • 46,916
  • 10
  • 92
  • 181
  • And what about the XHR request via `$.post`? – Gumbo Sep 11 '12 at 05: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 Sep 11 '12 at 05: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 Sep 11 '12 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 Sep 11 '12 at 18:03
  • Ah, never mind. I just forgot for one second that XHR does already send any existing cookies along. – Gumbo Sep 16 '12 at 06: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

CodeExpress
  • 2,422
  • 13
  • 10
  • 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. – Gaurav Sharma Sep 10 '12 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 Sep 10 '12 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: http://example.com/createuser.php?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'. – CodeExpress Sep 10 '12 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. – Gaurav Sharma Sep 11 '12 at 15:15