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?

  • 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, 2014 at 14:29
  • 17
    XSS always overrides CSRF - if you're vulnerable to the former then any CSRF protection is undermined. May 15, 2014 at 14:56
  • If the server has a weak CORS policy (null * and cache mistakes), then the cross origin javascript request might be triggered by the browser; tho custom header is better than nothing, but not the safy safest way
    – Xenos
    Nov 29, 2019 at 16:16

5 Answers 5


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:

  • 2
    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, 2014 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, 2014 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, 2014 at 3:03
  • @Gili They can't do this; I was mistaken. That said, it is absolutely possible to spoof the X-Requested-With header using Ajax, though of course the CORS policy still applies. Rook's response below demonstrates a vulnerability example; others may also exist (e.g. a CORS bypass in XMLHttpRequest which only works for JSON data).
    – Polynomial
    Jul 11, 2016 at 16:44
  • 1
    Here is a recent attack that circumvents a static header used as CSRF protection: insert-script.blogspot.cz/2018/05/… Of course, this specific attack applies to only a subset of IE users. Nonetheless,i t demonstrates why a static header is not a solid CSRF protection mechanism.
    – bayo
    May 4, 2018 at 9:59

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.


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
  • 1
    There are known, solid ways to protect against CSRF attacks (see @rook's answer below) and checking a static header value is not one of them. Here is a recent attack that proves this point: insert-script.blogspot.cz/2018/05/….
    – bayo
    May 4, 2018 at 10:05
  • @bayotop the owasp resource linked in rook's answer does in fact recommend validating the presence of a static header value. Jul 31, 2018 at 13:51
  • @JamesConkling No, it does not. The authors mention that they believe it's safe when combined with other checks ensuring the request's origin. Also the final note makes clear there is space for discussion. The attack I referenced above, bypasses these checks.
    – bayo
    Aug 1, 2018 at 14:22

EDIT: this csrf-request-builder was exploiting a vulnerability in Flash, which 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 Jersey is vulnerable to CSRF and the developers of Jersey have been notified. It is possible to leverage this vulnerability using Flash and possibly other scripting technologies. Jersey 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:


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.

  • 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/…? May 10, 2013 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, 2013 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. May 13, 2013 at 2:24
  • 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, 2013 at 16:32
  • 3
    The OWASP CSRF Prevention Cheat Sheet linked from this answer currently (last revision 2016-05-22) endorses the technique raised by the OP for "REST Services". (It mentions X-Requested-With header.) They do mention Flash vulnerabilities that undermine it, but say they believe that using it in conjunction with checking Origin header makes it secure.
    – JMM
    Jul 25, 2016 at 20:14

https://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.


As of 2020, MDN now explicitly recommends 'To prevent cross-origin writes, check an unguessable token in the request — known as a Cross-Site Request Forgery (CSRF) token'. See https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy (scroll down to 'How to block cross-origin access').

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .