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
add comment

2 Answers

up vote 7 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
add comment

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
add comment

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.