Take the 2-minute tour ×
Information Security Stack Exchange is a question and answer site for Information security professionals. It's 100% free, no registration required.

For a REST-api it seems that it is sufficient to check the presence of a custom header to protect against CSRF attacks, e.g. client sends

"X-Requested-By: whatever"

and the server checks the presence of "X-Requested-By" and drops the request if the header isn't found. The value of the header is irrelevant. This is how Jersey 1.9's CsrfProtectionFilter works and it is described in this blog post: http://blog.alutam.com/2011/09/14/jersey-and-cross-site-request-forgery-csrf/. The blog post also links to NSA and Stanford papers stating that the custom header itself is sufficient protection:

The first method involves setting custom headers for each REST request such as X-XSRF-Header. The value of this header does not matter; simply the presence should prevent CSRF attacks. If a request comes into a REST endpoint without the custom header then the request should be dropped.

HTTP requests from a web browser performed via form, image, iframe, etc are unable to set custom HTTP headers. The only way to create a HTTP request from a browser with a custom HTTP header is to use a technology such as Javascript XMLHttpRequest or Flash. These technologies can set custom HTTP headers, but have security policies built in to prevent web sites from sending requests to each other unless specifically allowed by policy. This means that a website www.bad.com cannot send a request to http://bank.example.com with the custom header X-XSRFHeader unless they use a technology such as a XMLHttpRequest. That technology would prevent such a request from being made unless the bank.example.com domain specifically allowed it. This then results in a REST endpoint that can only be called via XMLHttpRequest (or similar technology).

It is important to note that this method also prevents any direct access from a web browser to that REST endpoint. Web applications using this approach will need to interface with their REST endpoints via XMLHttpRequest or similar technology.

Source: Guidelines for implementing REST

It seems however, that most other approaches suggest that you should generate a token and also validate this on the server. Is this over-engineering? When would a "presence of" approach be secure, and when is also token validation required?

share|improve this question
    
What if the CSRF attack is generated by an injected script (for example, thru a stored XSS). This approach would not protect wrt this technique, if i am not wrong. –  user46678 May 15 at 14:29
2  
XSS always overrides CSRF - if you're vulnerable to the former then any CSRF protection is undermined. –  SilverlightFox May 15 at 14:56
    
This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post - you can always comment on your own posts, and once you have sufficient reputation you will be able to comment on any post. –  Steve May 15 at 16:50

4 Answers 4

up vote 9 down vote accepted

Security is about defence in depth. Simply checking the value is sufficient at the moment, but future technologies and attacks may be leveraged to break your protection. Testing for the presence of a token achieves the absolute minimum defence necessary to deal with current attacks. Adding the random token improves the security against potential future attack vectors. Using a per-request token also helps limit the damage done by an XSS vulnerability, since the attacker needs a way to steal a new token for every request they make.

This is the same reasoning used in modern cryptographic algorithms, where n rounds are considered a minimum for safety, but 2n+1 rounds (for example) are chosen in the official implementation to ensure a decent security margin.

Further reading:

share|improve this answer
    
I'm not sure what you mean by future attacks since the enctype mentioned in your link does not apply to the OP's extra header. Can you elaborate on that? Also, you mentioned limiting an XSS vulnerability, but I don't think CSRF token can help there. If the malicious XSS script can send requests, they can surely read the per-response CSRF token. What am I missing? –  Chris H. May 20 at 0:28
    
@ChrisH. Future technologies and changes to his site might allow an attacker to add the header. If I remember correctly, HTML5's web sockets now allow this. Changes to his site might also introduce a HTTP response splitting bug, which may also bypass header checks. Regarding the XSS comment, I'm referencing the fact that if you have an XSS on page A, having a dynamic token creates a requirement for the attacker to read page B, which might block the request based on X-Requested-With, or be filtered via CSP. –  Polynomial May 24 at 0:24
    
I can't find any proof that Web Sockets can be used to circumvent this protection, nor is it clear what you meant by "a HTTP response splitting bug". Can you please elaborate? –  Gili Jun 5 at 3:03

EDIT: this the csrf-request-builder was exploiting a vulnerability in Flash that has now been fixed. It is possible to send complex requests with JavaScript, however if you specify additional header elements a preflight OPTIONS http request will be sent prior to the actual request.

I have verified that Jersy is vulnerable to CSRF and the developers of Jersy have been notified. It is possible to leverage this vulnerability using Flash and possibility other scripting technologies. Jersy is vulnerable because the "X-Requested-By" http header is not on flash's header blacklist.

I used the CSRF-Request-Builder with the following arguments to build a post request:

file://var/code/CSRF-Request-Builder/csrf_payload.html#url=http://google.com&X-Requested-By=1&body={'test':1}

You should never come with with your own method of CSRF prevention unless you really understand CSRF exploitation. The CSRF Prevention Cheat sheet is a great resource.

share|improve this answer
    
Wouldn't whether the custom header gets sent be subject to the cross-domain policy for the remote site as per helpx.adobe.com/flash-player/kb/…? –  Simon Lieschke May 10 '13 at 1:34
    
@Simon Lieschke No this does not come into play, because a cross-domain policy is not loaded by this ActionScript client. This ability to control headers is not an ability granted by the "cross-domain policy", it is just native behavior. –  Rook May 10 '13 at 7:19
    
I'm unable to reproduce your example and can't get the CSRF-Request-Builder to perform a cross domain request with the X-Requested-By header. It always requests crossdomain.xml first and it only sends the POST request if the crossdomain.xml allows it with a line like <allow-http-request-headers-from domain="*" headers="X-Requested-By"/>. I tried with CSRF-Request-Builder hosted on the filesystem and loaded from another web server. I tested this with Flash 11.7.700.179 with Chrome 26.0.1410.64, Firefox 20.0.1 and Internet Explorer 9.0.8112.16421. –  Simon Lieschke May 13 '13 at 2:24
    
@Simon Lieschke something might have changed with the latest version of flash... let me check it out. –  Rook May 13 '13 at 16:05
2  
@Simon Lieschke So a few months ago, navigateToURL() didn't require a crossdomain.xml policy, it looks like this vulnerability has been patched and my exploit has been fixed. Oah well. It also looks like the CORS rules have changed to have a "preflight" options request for requests with special headers with JS. This type of attack is more difficult to carry out. You might want to post a question about this to all of security.se –  Rook May 13 '13 at 16:32

TL;DR - Checking the existence of a non-standard header like "X-Requested-By" should be sufficient to guard against CSRF attacks without checking the value of the header.

Non-standard headers cannot be set in a CSRF attack

The Play framework site breaks it down really well:

Simply put, an attacker can coerce a victims browser to make the following types of requests:

  • All GET requests
  • POST requests with bodies of type application/x-www-form-urlencoded, multipart/form-data and text/plain

An attacker can not:

  • Coerce the browser to use other request methods such as PUT and DELETE
  • Coerce the browser to post other content types, such as application/json
  • Coerce the browser to send new cookies, other than those that the server has already set
  • Coerce the browser to set arbitrary headers, other than the normal headers the browser adds to requests

This makes sense if you consider the attack vectors for CSRF:

  • GET requests (e.g. <img>, <iframe>) - which cannot set headers.
  • <form> submitted by a user click - which are limited to a few specific headers.
  • <form> submitted by JavaScript (HTMLFormElement.submit()) - which are limited to a few specific headers.

JavaScript is subject to the same-origin policy, so it can only add non-standard headers if one of the following conditions hold:

  • it is "in-domain" (i.e. loaded from the same domain as the target of the request).
  • it is allowed to do so through CORS.

XSS attacks are out of scope for this question

Non-standard headers can be set in an XSS attack. Using a non-standard header to prevent CSRF attacks does not make a site any more (or any less) vulnerable to XSS attacks regardless of the value of the header. Both non-standard headers and CSRF tokens are vulnerable to XSS attacks. If the XSS attacker can set a non-standard header on a request (e.g. in-domain XHR), he/she can certainly gain access to a CSRF token set in a cookie or embedded in DOM or in a JavaScript variable.

Reference

There is a similar SO question here which is confusing but came to the same conclusion.

Some examples of such non-standard headers in the wild:

  • "X-Requested-By" (mentioned by OP) recognized by Jersey/others
  • "X-Requested-With" set by jQuery
  • "X-XSRF-TOKEN" set by Angular
  • "X-CSRF-TOKEN" recognized by the Play framework
share|improve this answer

http://stackoverflow.com/a/11423778/14731 makes a very important point: the Same Origin Policy (SOP) is concerned with preventing the reading of cross-domain responses, not with the writing of requests.

Meaning, while you might be able to write custom headers in the future, it is extremely unlikely that you would ever be able to read the response of a cross-domain request. As such, the best CSRF protections involve reading a secret value from the server, writing it back, and having the server validate the value.

You don't necessarily need server-side state to accomplish this (Double-Submit Cookies, and Encrypted Token Pattern are two examples of this) but you should validate some secret value on the server.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.