How to modify Cookie from Ajax call


I have this code:

window.onload = function() {
        document.cookie = 'foo=bar; expires=Sun, 01 Jan 2012 00:00:00 +0100; path=/';
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "/showcookie.php",true);
        xhr.setRequestHeader("Cookie", "foo=quux");

        xhr.setRequestHeader("Foo", "Bar");
        xhr.setRequestHeader("Foo", "Baz");

        xhr.withCredentials = true;
        var pre = document.getElementById('output');
        xhr.onreadystatechange = function() {
            if (4 == xhr.readyState) {
                pre.innerHTML += xhr.responseText + "\n";
            }
        };
        xhr.send(null);
    };

and this /showcookie.php

<?php

print_r($_COOKIE);

?>

and it always show

Array
(
    [Host] => localhost
    [User-Agent] => 
    [Accept] => 
    [Accept-Language] => pl,en-us;q=0.7,en;q=0.3
    [Accept-Encoding] => gzip,deflate
    [Accept-Charset] => ISO-8859-2,utf-8;q=0.7,*;q=0.7
    [Keep-Alive] => 115
    [Connection] => keep-alive
    [foo] => Baz
    [Referer] =>
    [Cookie] => foo=bar
)

Array
(
    [foo] => bar
)

I'm using Firefox 3.6.13, Opera 11.00 and Chromium 9.0 on Ubuntu.

Is anybody have the same problem or maybe it's impossible to modify Cookie header.

The Cookie header is one of several which cannot be modified in an XMLHttpRequest. From the specification:

Terminate [execution of the setRequestHeader method] if header is a case-insensitive match for one of the following headers:

  • Accept-Charset
  • Accept-Encoding
  • Connection
  • Content-Length
  • Cookie
  • Cookie2
  • Content-Transfer-Encoding
  • Date
  • Expect
  • Host
  • Keep-Alive
  • Referer
  • TE
  • Trailer
  • Transfer-Encoding
  • Upgrade
  • User-Agent
  • Via

… or if the start of header is a case-insensitive match for Proxy- or Sec- (including when header is just Proxy- or Sec-).

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 think this might be a hard constraint on the XHR functionality.

Setting the clientside document.cookie caused the Cookie header to be sent in requests as expected. If you want to pass a cookie value in an an ajax request this might be the way to go.

A workaround is to send a custom header to the php script with the cookie string you want to set:

// in the js...
xhr.open("GET", "showcookie.php",true);
//xhr.setRequestHeader("Cookie", "foo=quux");
xhr.setRequestHeader("X-Set-Cookie", "foo2=quux");

xhr.withCredentials = true;

Then in your showcookie.php you can grab the custom header value and fire a set-cookie response header:

$cookie = $_SERVER['HTTP_X_SET_COOKIE'];

// NOTE: really should sanitise the cookie input.
header('Set-Cookie: ' . $cookie);


print_r($_COOKIE);

Note that you wont see a cookie header until the response is parsed by the browser. Also please make sure you sanitise the contents of the X_SET_COOKIE header - this is a proof of concept only:)