248

JQuery and other frameworks add the following header:

X-Requested-With: XMLHttpRequest

Why is this needed? Why would a server want to treat AJAX requests differently than normal requests?

UPDATE: I just found a real-life example using this header: https://core.spreedly.com/manual/payment-methods/adding-with-js. If the payment processor is requested without AJAX, it redirects back to the original website when it's done. When it is requested with AJAX, no redirection is done.

R andom
  • 101
  • 9
Gili
  • 76,473
  • 85
  • 341
  • 624

3 Answers3

284

A good reason is for security - this can prevent CSRF attacks because this header cannot be added to the AJAX request cross domain without the consent of the server via CORS.

Only the following headers are allowed cross domain:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type

any others cause a "pre-flight" request to be issued in CORS supported browsers.

Without CORS it is not possible to add X-Requested-With to a cross domain XHR request.

If the server is checking that this header is present, it knows that the request didn't initiate from an attacker's domain attempting to make a request on behalf of the user with JavaScript. This also checks that the request wasn't POSTed from a regular HTML form, of which it is harder to verify it is not cross domain without the use of tokens. (However, checking the Origin header could be an option in supported browsers, although you will leave old browsers vulnerable.)

New Flash bypass discovered

You may wish to combine this with a token, because Flash running on Safari on OSX can set this header if there's a redirect step. It appears it also worked on Chrome, but is now remediated. More details here including different versions affected.

OWASP Recommend combining this with an Origin and Referer check:

This defense technique is specifically discussed in section 4.3 of Robust Defenses for Cross-Site Request Forgery. However, bypasses of this defense using Flash were documented as early as 2008 and again as recently as 2015 by Mathias Karlsson to exploit a CSRF flaw in Vimeo. But, we believe that the Flash attack can't spoof the Origin or Referer headers so by checking both of them we believe this combination of checks should prevent Flash bypass CSRF attacks. (NOTE: If anyone can confirm or refute this belief, please let us know so we can update this article)

However, for the reasons already discussed checking Origin can be tricky.

Update

Written a more in depth blog post on CORS, CSRF and X-Requested-With here.

SilverlightFox
  • 28,804
  • 10
  • 63
  • 132
  • 17
    I don't get it. What prevents the attacker from building a request and adding a `X-Requested-With` header as well? – Greg May 15 '14 at 00:39
  • 15
    @Greg: The browser - it won't allow it cross-domain. – SilverlightFox May 15 '14 at 10:23
  • 2
    Oh, I didn't realize no CORS config would be needed as long as you are on the same domain. It's obvious though when you think about it. Thanks ! – Greg May 15 '14 at 22:20
  • This is still super annoying because it breaks a simple CORS setup which does not require a preflight OPTIONS request if no additional headers are present. I consider it a bug and have had to patch jQuery to *not* add it. – grae.kindel Oct 24 '14 at 20:01
  • @SilverlightFox so what stops someone from making requests outside of the browser? – vol7ron Mar 09 '15 at 17:49
  • 10
    @vol7ron: Nothing stops them, but then they won't have their victim's cookies in the request which defeats the object of them making the request. For a CSRF to succeed, the attacker would need the browser to automatically attach cookies with the request, so without the browser there is no CSRF attack. – SilverlightFox Mar 09 '15 at 18:03
  • 1
    @SilverlightFox, no, what I'm saying is it seems like there's a lot of security being enforced in the client, rather than the server. Is the point to prevent the client from running bad external code, or to prevent the client from accessing content they shouldn't be allowed to access? It makes sense for the first question, but the latter should be enforced at the server level, not by trusting the browser — anyone can fork/create a browser and take out security restrictions. – vol7ron Mar 10 '15 at 03:52
  • 4
    @vol7ron: The former. CSRF is a [confused deputy](http://en.wikipedia.org/wiki/Confused_deputy_problem) problem. The browser is the confused deputy and is "tricked" into sending cookies for a request the user didn't make themselves. – SilverlightFox Mar 10 '15 at 09:48
  • BTW, you can change the jQuery.ajax's X-Requested-With header value by "header" setting to make it more secure. Then check this value on the server side. http://api.jquery.com/jquery.ajax/ – starikovs Apr 23 '15 at 10:10
  • 1
    Why do we need CSRF tokens in addition to this? Wouldn't checking for this header be enough to prevent CSRF? – Ciro Santilli新疆棉花TRUMP BAN BAD May 15 '16 at 07:49
  • 1
    @ciro You don't, unless there's another bug in Flash (or similar plugin) that allows arbitrary headers to be set, bypassing the browser's usual restrictions. – SilverlightFox May 15 '16 at 07:53
  • Where are those allowed headers documented? I only see a blacklist at https://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader%28%29-method and https://xhr.spec.whatwg.org/#the-setrequestheader%28%29-method – Ciro Santilli新疆棉花TRUMP BAN BAD May 15 '16 at 08:16
  • 1
    @CiroSantilli巴拿馬文件六四事件法轮功: [Here](https://www.w3.org/TR/cors/#terminology), I believe. Although I believe there are some changes made during implementations to support other headers such as `Last-Event-ID`. – SilverlightFox May 16 '16 at 10:40
  • so `X-Requested-With` header can be added to a request that is for same origin without server responding with `Access-Control-Allow-Headers: X-Requested-With` in preflight? – Muhammad Umer Apr 17 '21 at 19:43
  • 1
    Yes @MuhammadUmer. For same origin requests, preflight is never needed. – SilverlightFox Apr 19 '21 at 07:01
32

Make sure you read SilverlightFox's answer. It highlights a more important reason.

The reason is mostly that if you know the source of a request you may want to customize it a little bit.

For instance lets say you have a website which has many recipes. And you use a custom jQuery framework to slide recipes into a container based on a link they click. The link may be www.example.com/recipe/apple_pie

Now normally that returns a full page, header, footer, recipe content and ads. But if someone is browsing your website some of those parts are already loaded. So you can use an AJAX to get the recipe the user has selected but to save time and bandwidth don't load the header/footer/ads.

Now you can just write a secondary endpoint for the data like www.example.com/recipe_only/apple_pie but that's harder to maintain and share to other people.

But it's easier to just detect that it is an ajax request making the request and then returning only a part of the data. That way the user wastes less bandwidth and the site appears more responsive.

The frameworks just add the header because some may find it useful to keep track of which requests are ajax and which are not. But it's entirely dependent on the developer to use such techniques.

It's actually kind of similar to the Accept-Language header. A browser can request a website please show me a Russian version of this website without having to insert /ru/ or similar in the URL.

EWit
  • 1,848
  • 13
  • 20
  • 18
  • 31
    Wow, that sounds like a horrible maintenance nightmare. If you want to return a different representation of the same page, you should provide a different content-type to the `Accept` header. Using a custom header for this sounds like the wrong way to go. – Gili Jul 06 '13 at 01:52
12

Some frameworks are using this header to detect xhr requests e.g. grails spring security is using this header to identify xhr request and give either a json response or html response as response.

Most Ajax libraries (Prototype, JQuery, and Dojo as of v2.1) include an X-Requested-With header that indicates that the request was made by XMLHttpRequest instead of being triggered by clicking a regular hyperlink or form submit button.

Source: http://grails-plugins.github.io/grails-spring-security-core/guide/helperClasses.html

Koray Güclü
  • 2,684
  • 1
  • 31
  • 30