What's the point of the X-Requested-With header?
Asked Answered
C

3

301

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.

Cyanine answered 4/7, 2013 at 22:17 Comment(3)
"[When] requested without AJAX, it redirects back to the original website when it's done. When it is requested with AJAX, no redirection is done." -> That's exactly why you would want to do it. :)Sadoc
#3316414Saccharin
Another use case: an application I worked on redirects unauthenticated users to the login page on regular requests. If the request was through AJAX (detected with this header), no redirection occurs if the user is unauthenticated, but an error is returned. The Django web programming framework has an is_ajax function to detect ajax calls using this header.Trenchant
C
331

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 across origins:

  • 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.

Concord answered 20/3, 2014 at 12:54 Comment(19)
I don't get it. What prevents the attacker from building a request and adding a X-Requested-With header as well?Otoole
@Greg: The browser - it won't allow it cross-domain.Concord
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 !Otoole
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.Kazan
@Concord so what stops someone from making requests outside of the browser?Tris
@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.Concord
@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.Tris
@vol7ron: The former. CSRF is a confused deputy problem. The browser is the confused deputy and is "tricked" into sending cookies for a request the user didn't make themselves.Concord
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. api.jquery.com/jquery.ajaxBespoke
Why do we need CSRF tokens in addition to this? Wouldn't checking for this header be enough to prevent CSRF?Saccharin
@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.Concord
Where are those allowed headers documented? I only see a blacklist at w3.org/TR/XMLHttpRequest/#the-setrequestheader%28%29-method and xhr.spec.whatwg.org/#the-setrequestheader%28%29-methodSaccharin
@CiroSantilli巴拿馬文件六四事件法轮功: Here, I believe. Although I believe there are some changes made during implementations to support other headers such as Last-Event-ID.Concord
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?Lymphocytosis
Yes @MuhammadUmer. For same origin requests, preflight is never needed.Concord
Is 'X-Requested-With' header effective for preventing login CSRF attack? cheatsheetseries.owasp.org/cheatsheets/… mentions use of pre-sessions and including token in login form, but does not say whether 'X-Requested-With' header can also prevent it.Selfrenunciation
@phalgun Yes, if the server is validating the header before starting a session. This would be in the case of an AJAX request for login where cookies authenticate the session. If a bearer token in the header authenticates the session, then it's not vulnerable anyway without CORS giving the attacker's site permission to read the response containing the token.Concord
@Concord Does it also hold true for basic authentication? Also, I see long back Djano(CVE-2011-0696) and Ruby on Rails(CVE-2011-0447) were vulnerable to CSRF due to the use of X-Requested-With header. It says the attackers could forge AJAX/API requests through "combination of browser plugins and redirects". Since this was more than a decade ago, has forging AJAX/API requests become more difficult now?Selfrenunciation
@phalgun Basic auth isn't vulnerable to login csrf as it's header based. As mentioned in my reply, plugins such as Flash opened up holes in the browser security model. These days the HTML Living Standard can handle most requirements without the need for Flash or other plugins.Concord
M
35

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.

Moreira answered 4/7, 2013 at 22:48 Comment(1)
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.Cyanine
C
14

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

Commonality answered 28/1, 2015 at 9:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.