0

I have a scenario where I already have CSRF tokens, but I have to remove. On an ecommerce, the product page is cached by Varnish, so if the user lands directly here, he won't have a session ID to validate the token. In this page I have a "add to cart" button which have the CSRF token, but of course it's cached with the wrong token.

My question is: there is another way to have a CSRF protection without relying on a input hidden with the token? The page where the button is placed must be cached, so tokens in this case aren't good.

Thanks.

Rafael Kassner
  • 1,123
  • 6
  • 21

3 Answers3

3

For a CSRF token to be effective, you need to be able to submit it outside of the cookie mechanism. You could make your page execute an AJAX POST to your site in order to retrieve the CSRF token.

e.g. https://www.example.com/GetCSRFToken

Response:

{ "token": "abcdefg" }

Then you will be able to submit this token with your form. As this is a separate request, the response will not be part of your cached page. The only drawback with this method is that JavaScript must be enabled for the token to be retrieved. It might be possible for you to handle this scenario though, and if a form is POSTed without the token due to JavaScript being disabled you could add a confirmation step before the actual item is added to the cart. The confirmation page would be set not to be cached so each user would always get the token for their session.

SilverlightFox
  • 32,436
  • 11
  • 76
  • 145
  • Is this just the same as not having any CSRF token and relying on same origin policies? Since the only way you could secure `/getCSRFToken` is via same origin policy otherwise, one could mount a CSRF attack by simply doing two posts instead of one (the first post, being to get the CSRF token and the second request would be the attack request), unless I'm missing something about how `/GetCSRFToken` is secured? – Adam Terrey Aug 15 '17 at 03:41
  • You can't retrieve values in a csrf attack, you can only send them. Same Origin Policy allows writes, not reads hence why you need CSRF mitigation for writes. By writes I mean POST requests or other 'non safe' methods. Does this answer what you are asking? – SilverlightFox Aug 15 '17 at 05:50
  • Or have I misunderstood your question? I'm guessing it is your downvote? – SilverlightFox Aug 15 '17 at 10:12
  • The token is retrieved in the response body, not cookie, and stored in the dom. A 3rd party domain won't be able to retrieve and store in the dom due to the sop. – SilverlightFox Aug 15 '17 at 10:20
  • I think your right, I'll un-down vote this. But still cautious about this implementation. Do you think a request to a `/SetCSRFTokenCooke` would work? I'm a little more confident to do it that way. – Adam Terrey Aug 16 '17 at 06:33
  • What would this request do? What are its inputs and outputs? – SilverlightFox Aug 16 '17 at 15:11
1

There is an alternative described at OWASP CSRF Prevention Cheat Sheet titled "Double Submit Cookies"

It submitting Session ID with the form, where javascript reads this cookie value and injects it as a hidden input element to the form. For this to work, your session cookies must not be marked as HTTPOnly, which is a bad practice. So you lose some session cookie security while trying to add some on CSRF.

As an improvement to this method, you can create another cookie with login that stores CSRF token value and use this cookie instead of the sessionid cookie. Now you can mark sessionid cookie as HTTPOnly. (Not marking csrf cookie as httponly is also a bad practice but not critical as before)

(I assume retrieving csrf token via AJAX calls on every page is not an option for performance reasons)

SilverlightFox
  • 32,436
  • 11
  • 76
  • 145
mesutozer
  • 2,839
  • 1
  • 12
  • 13
-1

You can use cookies for the CSRF, the cookie is set on the form page and checked on the next one. It may require some tweaks but it will get around the caching.

Don't forget to configure Varnish to not drop that cookie.

Rafael Dohms
  • 207
  • 2
  • 8
  • You don't want to cache a page with a set-cookie otherwise everyone will get that same cookie. – dalore Dec 20 '18 at 11:23