Why cookies and set-cookie headers can't be set while making xmlhttprequest using setRequestHeader?
Asked Answered
W

8

39

I was wondering why one cannot set cookie headers using setRequestHeader. Is there any specific reason or just that they are added by browser itself, so these headers are disabled? Is there any security issue?

--Edit

I am working on node.js and used the xmlhttprequest module. Following is the test code:

var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.withCredentials = true;
xhr.setRequestHeader('Cookie', "key=value");
xhr.send(null);

Here I need to set cookie-header as node.js' xmlhttprequest do not explicitly adds cookie-header(as browsers do). When trying to do so, xmlhttprequest gives error "Refused to set unsafe header".

Though I have found a patch and successfully able to send the cookie-header. But was wondering why it was disabled to set cookie-header? Where-ever I read, found that it is required for data-integrity and security, but what security can be breached in this case, is mentioned no where. I want to evaluate if, this data-integrity problem is valid for node.js application as well if I go with my patch.

Wheelsman answered 4/3, 2013 at 9:26 Comment(1)
Can you post the piece of code which actually made you think this? or Is it just the specification document ...Hockenberry
H
26

I am sure you would have gone through the working draft and found

The above headers are controlled by the user agent to let it control those aspects of transport.

Firstly we need to understand, These are standards working as guidelines for interoperability of functions between different browsers. It's not mandated for the browser and hence browsers do have different level of adherence to this standard for different reasons.

Secondly, Technically speaking you can emulate a user agent , treat your program as the browser and can very well set those values as per mentioned standards.

Finally, the intent of disallowing overwriting of Headers or setting up headers for certain fields like Content-Length , Cookie ethos the secure design approach. It is to discourage or at least try to discourage HTTP Request smuggling.

Hockenberry answered 7/3, 2013 at 8:57 Comment(1)
Manish ,can you assume that i can hard code the username and password which is asked in javascript prompt. I cannot set it false. I need to provide it. Is it possible by stetting a cookie by default. Thanks for insight.Telethermometer
A
18

You can disable this behaviour:

var xhr = new XMLHttpRequest();
xhr.setDisableHeaderCheck(true);
xhr.open(...);
...
Ambivert answered 7/3, 2013 at 9:19 Comment(6)
Hi @robertklep, where on earth have you found spec on setDisableHeaderCheck ? could you point me to a doc or something ? also this does not work/is not implemented in chrome 22. Edit: it's not event in canariVitalize
@MarcelFalliere we're talking about the node-XMLHttpRequest library (which implements it here), not the XMLHttpRequest in a browser :)Ambivert
Are you kidding me ? there is no such function as XMLHttpRequest.setDisableHeaderCheck(true)Steerage
@ShailendraSinghRajawat again, see this piece of code.Ambivert
hmmm ... seems it require some external lib integration... thnx for the link, but is there any direct way to do it on chrome for android ?Steerage
@ShailendraSinghRajawat as I explained in the comments here before: my answer is not related to XMLHttpRequest in browsers, but to the Node.js module node-XMLHttpRequest. The OP was having issues with this module, and I provided a possible answer for that specific environment, not a generic answer that works in browsers.Ambivert
V
8

As is well known, for browsers, cookies (among other properties) need to be carefully managed to prevent third parties from stealing user sessions (or other data). This is an issue with browsers, and the uncontrolled nature of visiting a website that runs arbitrary Javascript.

Of course this risk of arbitrary code execution is either a low or non-risk for node.js, as you only run a script which you wrote which may run other code you planned for.

If you have a look at the source code for driverdan's XMLHttpRequest.js you will find:

 // These headers are not user setable.   
 // The following are allowed but banned in the spec:   
 // * user-agent   
 var forbiddenRequestHeaders = [
    "accept-charset",
    "accept-encoding",
    "access-control-request-headers",
    "access-control-request-method",
    "connection",
    "content-length",
    "content-transfer-encoding",
    "cookie",
    "cookie2",
    "date",
    "expect",
    "host",
    "keep-alive",
    "origin",
    "referer",
    "te",
    "trailer",
    "transfer-encoding",
    "upgrade",
    "via"   ];

This answer your specific question of why the restriction particularly applies to this script used for node.js - the coder was following the spec (as closely as possible), despite that feeling it probably wasn't a required security precaution in node.js. Nevertheless this default security level is readily modified.

As robertklep pointed out, you can disable this default precaution by using the setDisableHeaderCheck method. And yes this final point does answer or contribute significantly toward an answer for your question because in your question you stated:

I have found a patch and successfully able to send the cookie-header

We have now found you didn't need that patch.

Good Luck!

Vishinsky answered 11/3, 2013 at 7:19 Comment(0)
R
4

Yes, it is required for data-integrity and security. To understand this, you have to understand the role of cookies in HTTP request methods.

Cookies are important in identifying the user, browser, connection etc and are stored at web browser. JavaScript allows you to manipulate cookies, but not all cookies on the browser. See HTTP cookies, these are only set by browser, so that user can't misuse it (via JavaScript).

On a supported browser, an HttpOnly session cookie will be used only when transmitting HTTP (or HTTPS) requests, thus restricting access from other, non-HTTP APIs (such as JavaScript).

When you send xmlhttprequest it reads HttpOnly cookies and sends to server via Cookie header. Now if you do xhr.setRequestHeader('Cookie', "key=value"); , you are trying to tamper with the cookies sent to server. setRequestHeader will add extra key=value that may compromise the integrity of the cookies sent.

These are used by server to authenticate the user (session, email-account or any account). This essentially allows server to prevent misuse of cookies to get access into server.

Renferd answered 8/3, 2013 at 18:25 Comment(0)
S
2

the documentation mentions that this is done to protect data integrity. http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader%28%29-method

The above headers are controlled by the user agent to let it control those aspects of transport. This guarantees data integrity to some extent. Header names starting with Sec- are not allowed to be set to allow new headers to be minted that are guaranteed not to come from XMLHttpRequest.

Stegodon answered 6/3, 2013 at 12:36 Comment(1)
Sorry, because of my little experience in developing web-apps, can't get it properly. Can you please explain with example - what kind of data-integrity is protected by doing so?Wheelsman
M
1

I was able to resolve this problem using the following Gist:
https://gist.github.com/killmenot/9976859

The original idea is taken from here:
https://gist.github.com/jfromaniello/4087861

I faced with several problems:

  1. Source Gist is outdated and doesn't work for me. For example "request" lib API was changed.
  2. I might work with socket.io-client's "xmlhttprequest" library and don't install on the same level with socket.io-client.
  3. Original "socket.io-client" (0.9.16) uses "xmlhttprequest" (1.4.2) that doesn't support "setDisableHeaderCheck" method (but 1.6.0 does). So, I make a fork and use it https://github.com/intspirit/socket.io-client/tree/0.9.16+20140408120400

socket.io-client (1.0.0-pre) uses engine.io-client that uses correct version of xmlhttprequest. I guess in the future I'll use 1.0.0 version instead of my fork, specify "xhr-polling" transport and mock XMLHttpRequest as the original gist does.

Maypole answered 8/4, 2014 at 11:44 Comment(1)
No amount of patching or libraries could get through the restriction by browsers when attempting to send cookies across origins. The gist sends cookie to own origin, which can be done with the regular document.cookie interface (see MDN).Divorcement
D
-1

I think this answers are not sufficiently complete.

Just as all of the asnwers says, you can't use xhr.setRequestHeader('Cookie', "key=value"); to send any data because of security integrity (the browser can't tell if the value you are adding is a real cookie).

The expected way to work with this special header is to let the client browser automatlycally take all the cookies related to the site you are requesting and put them on the 'Cookie' header, you don't need to do anything else, if your cookies exist in your browser, they will be send.

...And if you are wondering, all the cookies stored in your browser are suposed to be stored/updated everytime a response from the server you are requesting sends you back a Set-Cookie header. So it has no sense add a 'Set-Cookie' header in a request because it is a header reserved for responses only, and is not needed to add a 'Cookie' header in your requests because your browser is already doing it.

Dianndianna answered 30/9, 2019 at 18:48 Comment(0)
T
-1

add xhr._restrictedHeaders.cookie = false before xhr.setRequestHeader('Cookie', "key=value"); but it's bad way, I'm not recommnend using it.

Translocation answered 15/1, 2022 at 5:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.