1

I understand that CSRF is a major security concern for HTTP(S)-based applications.

From the looks of it, most frameworks send the CSRF token as part of the request body. However, in my case that is somewhat inelegant for several reasons; most importantly I don't want to mess with the transport layer which might send POST requests in many different formats, not necessarily all are JSON or x-www-form-urlencoded.

As a solution, I was thinking of a much less intrusive alternative; particularly, I am generating a random header: A randomized header name (common prefix), containing a random CSRF token.

Is there any security (or other kind of) risk to that?

Domi
  • 22,151
  • 15
  • 92
  • 122
  • I don't see any particular reason for randomizing the header *name*. Just make sure it doesn't collide with any standard (or commonly used non-standard) headers. Something like `X-YourAppName-CSRF` should be a reasonable name. – Ilmari Karonen Apr 30 '15 at 11:37
  • @IlmariKaronen: Diverging from the norm makes my application safer against [scriptkiddies](http://en.wikipedia.org/wiki/Script_kiddie) who use tools with limited capabilities (e.g. tools that are unable to cope with changing header names). On the other side of the trade-off curve (value-added vs. cost-added): Working with a pair of tokens instead of just one token comes at very little development and maintenance overhead. – Domi May 01 '15 at 12:47

2 Answers2

2

You could just set the X-Requested-With header and then check for this server side. Many frameworks, like JQuery, add this automatically to AJAX requests.

X-Requested-With is a de-facto standard for indicating that the request is made via AJAX.

You do not need a random token as it is not possible for this header to be sent cross domain without the server opting in via CORS.

Therefore, setting and checking a non-standard header is a valid way to protect against CSRF.

The OWASP CSRF Prevention Cheat Sheet does not mention it, however it does mention checking the Origin header. However, the logic for this is not straightforward as many browsers do not send Origin for same origin requests.

Also this only works for AJAX requests. With a normal form POST it is not possible to add extra headers. Also, in the past there have been bugs with plugins like Flash that allowed any header to be set enabling an attacker to use Flash to make a cross-domain request. However, issues like these have long since been patched.

If you want a token as well as part of a defence in depth strategy, you could adapt X-Requested-With to include a random token that you then check. e.g. X-Requested-With: XMLHttpRequest;0123456789ABCDEF.

Then token could simply be a cookie value created just for CSRF prevention purposes (generated with a cryptographically secure algorithm and entropy source of course).

Community
  • 1
  • 1
SilverlightFox
  • 32,436
  • 11
  • 76
  • 145
  • Sounds like a great and simple idea! I wonder why the [OSWAP CSRF Prevention Cheat Sheet](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet) does not even mention it. On the other hand, it's not quite as safe: 1. I assume that some servers enable [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) by default, or have it enabled for other reasons (e.g. due to unaware developers). 2. Use of security tokens reduces the risk posed by attackers who can sneak in [same-origin](http://en.wikipedia.org/wiki/Same-origin_policy) requests. – Domi May 01 '15 at 12:39
  • 1
    @Domi: The main reason is that this only works for AJAX requests. With a normal form POST it is not possible to add extra headers. Also, in the past there have been bugs with plugins like Flash that allowed any header to be set enabling an attacker to use Flash to make a cross-domain request. However, issues like these have long since been patched. – SilverlightFox May 01 '15 at 12:42
  • Browser bugs are always something to take into consideration! It appears, I am better off sticking to my random header + security token, nevertheless :) [Btw: I re-wrote my original comment] – Domi May 01 '15 at 12:44
  • @Domi: Generally you shouldn't be coding round weaknesses in the browser - you have to trust the client side of the contract to uphold their side of security. Nowadays browsers auto update so it is a low risk. You could adapt `X-Requested-With` to include a random token that you then check. e.g. `X-Requested-With: XMLHttpRequest;0123456789ABCDEF`. – SilverlightFox May 01 '15 at 12:48
  • @Domi: Also note that if CORS is accidentally enabled, it will be allowing GET access to any token anyway, and there is no risk of "same-origin requests being sneaked" without a vulnerability to make this possible. – SilverlightFox May 01 '15 at 12:51
  • When I make security considerations, I like to work under worst-case assumptions. Risk of anything is always greater 0. Which is why I seek to categorically eliminate contributors to risk. And that includes possibilities of 1) a security bug in the browser (ever-green or not), as well as 2) attackers already being able to execute requests under the same-origin policy (for whatever reason). – Domi May 01 '15 at 13:09
  • One more thing: What do you mean by "GET access to any token"? CORS seems to be safe there: "[JavaScript code can’t access the cookies from document.cookie or the response headers](http://www.html5rocks.com/en/tutorials/cors/)" -- In fact, that largely speaks in favor of sending security tokens in headers instead of the body! – Domi May 01 '15 at 13:10
  • 1
    @Domi: Before transmission of the token in the POST, it must be transmitted to the client somehow. I mentioned GET would be accessible via CORS because you were mentioning the Synchronizer Token Pattern in your original comment. However if you are using Double Submit Cookies then this GET is not required. – SilverlightFox May 01 '15 at 13:21
  • @Domi: Need any further help with this? – SilverlightFox Nov 07 '15 at 11:30
1

Is there any security (or other kind of) risk to that?

There is no: as soon as you can pass it from the client and check on the server - you're fine

Also, how often should I refresh the CSRF token? Do I need a new one for every request, or every few requests, or once per site-visit and day, or...?

Generally you should not refresh it at all. If it's generated using cryptographically strong random number generator - you can have one per session. What important is that it was not possible to guess it, so it should not derive from any known data.

zerkms
  • 249,484
  • 69
  • 436
  • 539
  • 2
    As per @Quentin's suggestion, I removed the second question. I already found a great answer to it [here](http://security.stackexchange.com/questions/22903/why-refresh-csrf-token-per-form-request) :) – Domi Apr 30 '15 at 08:46