简体   繁体   中英

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

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.

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 .

You can disable this behaviour:

var xhr = new XMLHttpRequest();
xhr.setDisableHeaderCheck(true);
xhr.open(...);
...

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!

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.

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.

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.

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM