How Different Browsers Handle Cookies Differently

24-JUL-2011, last update 14-DEC-2014
A cookie is a piece of data that a website can store in user's browser. You can find a lot of good information about these HTTP Cookies on Wikipedia. The specification can be found in RFC 6265.

This article describes how they are implemented in the different brands of web browsers, and focuses on the differences. Some differences are quite shocking! The article might explain some odd behavior you have seen from time to time, or explain incident reports from your users.

Table of Contents

Introduction - The Basics

A web site can write a cookie using a Set-Cookie response header. In its simplest form, it will only contain a name-value pair, for example:

  Set-Cookie: test=helloworld;

There are many attributes that can be used on a cookie response header, such as adding a domain, path and expires information. Here is an example with many of such attributes:
  Set-Cookie: test=helloworld; expires=Thu, 01-Jan-1970 00:00:10 GMT; domain=.mydomain.com; path=/; HttpOnly; Secure

The web browser will or will not accept the cookie that the web server tries to set. It will not tell the user, although the browser might ask the user whether or not to accept the cookie.

Whenever a page is requested from the web server, the browser will check whether it needs to send a cookie (or multiple cookies). If it does, it will send a request header like this:

  Cookie: test=helloworld;

The browser will not send any of the other information it might have received, such as when the cookie expires, the path or whether it is a secure cookie.

It is not only the server that can set cookies. In most situations, it is also possible to set cookies using client-side Javascript.

This article describes the effect of the different properties and situations regarding cookies.

Effects of PATH

The web server can use the path attribute to specify what URL paths qualify for the cookie. for example:

  Set-Cookie: test=helloworld; path=/products;

The path in the example indicates that only URLs that start with "/products" should use the cookie. So a URL like http://www.mydomain.com/products/ball.html should use it, and a URL like http://www.mydomain.com/introduction.html should not.

It also means that in this example, on page http://www.mydomain.com/products/ball.html the DOM would expose the "test=helloworld" information in the document.cookie object, accessible with Javascript, but document.cookie would be empty for Javascript that is executed in the context of http://www.mydomain.com/introduction.html

Set-cookie - Path

It is perfectly valid for page like http://mydomain.com/goodbye/world.htm to write a cookie with the path /hello. When setting cookies, the path does not have to match.

Cookie matching - Path

There are URLs in different shapes and forms. Here are a few examples:

The table below shows for each brand of web browser whether it considers the URL to match the path.
The browser will only send it to the server if it matches.

Cookie pathWhen requesting URLSafari 5,
Chrome 12,
Opera 10,
Netscape 4
FireFox 3,
FireFox 5,
FireFox 23
Internet Explorer 6,
Internet Explorer 7,
Internet Explorer 8,
Internet Explorer 9,
Internet Explorer 10
path=/hellohttp://mydomain.com/goodbye/world.htmno matchno matchno match
path=/hellohttp://mydomain.com/hello/world.htmmatchmatchmatch
path=/hello/world.htmhttp://mydomain.com/hello/world.htmmatchmatchmatch
path=/hello/world.htmhttp://mydomain.com/hello/world.htm?id=5matchmatchmatch
path=/hello/world.htm?id=5http://mydomain.com/hello/world.htmno matchno matchMATCH!
path=/hello/world.htm?id=5http://mydomain.com/hello/world.htm?id=5NO MATCH!matchmatch

As you can see in the table, different browser behave differently when query string parameters are used in the cookie path. Therefore, I recommend against using parameters in the cookie path.

The table below shows for each brand of web browser if the cookie is exposed to Javascript based on the path matching.

Cookie pathJavascript on page at URLSafari 4,
Safari 5,
Chrome 28
FireFox 14,
FireFox 22
Internet Explorer 7,
Internet Explorer 9,
Internet Explorer 10
path=/hellohttp://mydomain.com/goodbye/world.htmnot exposednot exposednot exposed
path=/hellohttp://mydomain.com/hello/world.htmexposedexposedexposed
path=/hello/world.htmhttp://mydomain.com/hello/world.htmexposedexposedNOT EXPOSED!
path=/hello/world.htmhttp://mydomain.com/hello/world.htm?id=5exposedexposedNOT EXPOSED!
path=/hello/world.htm?id=5http://mydomain.com/hello/world.htmnot exposednot exposednot exposed
path=/hello/world.htm?id=5http://mydomain.com/hello/world.htm?id=5NOT EXPOSED!exposedNOT EXPOSED!

In addition to the earlier recommendation never to use query string parameters in the cookie's path, this table shows that is it best not to use the actual page name in the path either. As the name suggests, it is best to use the cookie path only for the path of a web page.

Effects of DOMAIN

The web server can use the domain attribute to specify what URL domain names qualify for the cookie. For example:

  Set-Cookie: test=helloworld; domain=.mydomain.com;

The domain in the example indicates that only URLs that are "mydomain.com", or are subdomains of it should use the cookie. So a URL like http://www.mydomain.com/products/ball.html should use it, and a URL like http://cnn.com/ should not.

Set-cookie - Domain

The table below shows how web browsers react if no domain is present in the Set-Cookie header.

If the cookie is accepted, it is only used for the exact domain of the requested URL.

Requested URL domain omitted
in the
Set-Cookie header
Safari 5,
Chrome 12,
Opera 11,
FireFox 3,
FireFox 5,
FireFox 23,
Internet Explorer 6,
Internet Explorer 7,
Internet Explorer 8,
Internet Explorer 9,
Internet Explorer 10
Netscape 4 Internal
representation
of domain
http://go/ acceptednot acceptedgo
http://go.go/ acceptednot acceptedgo.go
http://good.go/ acceptedacceptedgood.go
http://www.good.go/ acceptedacceptedwww.good.go

Because of security reasons, a page is not allowed to set cookies for another domain. It is only allowed to specify the current domain or higher levels of that domain, up to and including the second level domain.

For example a page at http://this.is.an.example.com/ is allowed to specify the domains this.is.an.example.com, is.an.example.com, an.example.com and example.com.

The table below shows for each brand of web browser whether it will accept the returned cookie with a specified domain for the requested URL.

If the cookie is accepted, it is used for the specified domain and all its subdomains. Typically, this behavior is expressed with a "wildcard" dot prefixed to the domain in the internal representation.

Requested URL domain
in the
Set-Cookie header
FireFox 3,
FireFox 5, FireFox 33
Internet Explorer 6 - 11 Safari 5 Chrome 12 Netscape 4 Opera 11 Internal
representation
of domain
http://go/domain=goacceptednot acceptedacceptednot acceptednot acceptedaccepted.go
http://go/domain=.goacceptednot acceptedacceptednot acceptednot acceptedaccepted.go
http://go.go/domain=gonot acceptednot acceptedACCEPTED!not acceptednot acceptednot accepted.go
http://go.go/domain=.gonot acceptednot acceptedACCEPTED!not acceptednot acceptednot accepted.go
http://go.go/domain=go.goacceptedNOT ACCEPTED!acceptedacceptedNOT ACCEPTED!accepted.go.go
http://go.go/domain=.go.goacceptedNOT ACCEPTED!acceptedacceptedNOT ACCEPTED!accepted.go.go
http://good.go/domain=good.goacceptedacceptedacceptedacceptedNOT ACCEPTED!accepted.good.go
http://good.go/domain=.good.goacceptedacceptedacceptedacceptedNOT ACCEPTED!accepted.good.go
http://www.good.go/domain=good.goacceptedacceptedacceptedacceptedNOT ACCEPTED!accepted.good.go
http://www.good.go/domain=.good.goacceptedacceptedacceptedacceptedacceptedaccepted.good.go
http://www.good.go/domain=www.good.goacceptedacceptedacceptedacceptedacceptedaccepted.www.good.go
http://good.go/domain=www.good.gonot acceptednot acceptednot acceptednot accepted??.www.good.go
http://also.good.go/domain=www.good.gonot acceptednot acceptednot acceptednot accepted??.www.good.go

As you can see, there are a few remarkable things in this table:
I therefore recommend that you run your website on a second level domain where your second level consists of at least 3 characters (for example cnn.com), or use a third level domain (for example www.hi.nl).

Cookie matching - Domain

Once the browser has accepted a cookie for a domain or domain hierarchy, it will use that information to determine whether the cookie should be sent when requesting a URL.

The table below shows for each brand of web browser whether it considers the URL to match the domain of the available cookie.

Note that domains without a leading dot can only result from a Set Cookie operation that did not specify a domain. The leading dot in the Cookie domain is a wildcard to indicate a domain hierarchy.

Internal
representation
of domain
When requesting URLFireFox 3,
FireFox 5,
FireFox 12
Internet Explorer 6,
Internet Explorer 7,
Internet Explorer 8,
Internet Explorer 9,
Internet Explorer 10
Safari 5 Chrome 12,
Chrome 36
Opera 11 Netscape 4
domain=gohttp://go/matchno matchmatchno matchmatchno match
domain=.gohttp://go/matchno matchmatchno matchmatchno match
domain=gohttp://good.go/no matchno matchmatchno matchno matchno match
domain=.gohttp://good.go/no matchno matchmatchno matchno matchno match
domain=good.gohttp://good.go/matchmatchmatchmatchmatch?
domain=good.gohttp://www.good.go/no matchMATCHno matchno match?NO MATCH!
domain=.good.gohttp://www.good.go/matchmatchmatchmatchmatchmatch
domain=www.good.gohttp://good.go/no matchno matchno matchno matchno matchno match
domain=www.good.gohttp://www.good.go/matchmatchmatchmatchmatchmatch

The big surpise in this table, is that Internet Explorer will use cookies for subdomains that were issued specifically for the main domain.

Cookie matching - Domain - Multiple matches

If you request a URL, cookies from multiple domains might apply. For example, when requesting http://this.is.an.example.com/ there may be cookies for the exact domain this.is.an.example.com and for the wildcard domains .this.is.an.example.com, .is.an.example.com, .an.example.com and .example.com.

When multiple cookies apply, the browser may choose to send one, some or all of them as part of the Cookie request header. For example, the browser might send the following header.
  Cookie: test=one; test=two

Typically, when the application on the server inspects the cookie ("test" in the example), the first value is returned ("one" in the example).

The table below shows for each brand of web browser in which order multiple cookies are reproduced.

Requested
domain
at T=0
Set-Cookie header
at T=0
Requested
domain
at T=1
Set-Cookie header
at T=1
Requested
domain
at T=2
FireFox 31,
Chrome 36,
Internet Explorer 10
Safari 5,
Safari 6
good.goSet-Cookie: x=2; domain=good.gowww.good.goSet-Cookie: x=0 www.good.goCOOKIE: X=2; X=0 Cookie: x=0; x=2
www.good.goSet-Cookie: x=0good.goSet-Cookie: x=2; domain=good.go www.good.goCookie: x=0; x=2 Cookie: x=0; x=2
good.goSet-Cookie: x=2; domain=good.gowww.good.goSet-Cookie: x=3; domain=www.good.go www.good.goCOOKIE: X=2; X=3 Cookie: x=3; x=2
www.good.goSet-Cookie: x=3; domain=www.good.gogood.goSet-Cookie: x=2; domain=good.go www.good.goCookie: x=3; x=2 Cookie: x=3; x=2

As you can see, FireFox, Chrome and Internet Explorer list the cookies in order of creation instead of order of precedence. Since the context (the internal representation of the domain) is not sent in the Cookie header - and therefore cannot be established by the server - it is the browser's responsibility to send the cookie with the most selective domain first, the way Safari does it.

Effects of HTTPONLY

The web server can use the HttpOnly attribute to specify that the cookie use should be restricted to the HTTP(S) connection. In other words, it will not be exposed in the DOM; it will not be available in Javascript.

  Set-Cookie: test=helloworld; HttpOnly;

In the example, the cookie test would not be available in any client-side Javascript code.

The table shows for each brand of web browser if it exposes the cookie to Javascript when the HttpOnly attribute was used when the cookie was set.

Cookie HttpOnlyJavascript on page at URLSafari 4,
Safari 5,
Safari 6,
Opera 12,
Chrome 28,
Internet Explorer 7,
Internet Explorer 9,
Internet Explorer 10,
FireFox 22
HttpOnlyhttp://mydomain.com/hello/world.htmnot exposed,
DOM cookie cleared

The next table shows what happens if Javascript attempts to write a cookie that is already available as HttpOnly cookie.

Cookie HttpOnlyJavascript writes the same cookieSarari 4,
Safari 5,
Safari 6,
Opera 12
Chrome 28,
Internet Explorer 7,
Internet Explorer 9,
Internet Explorer 10,
FireFox 22
test=helloworld; HttpOnly;document.cookie='test=bye';COOKIE IS OVERRIDDEN!
HttpOnly status is lost
Javascript is ignored

What this table shows, is that Safari and Opera provide only half the protection that might be expected from the HttpOnly attribute. Although they do prevent exposure to any Javascript, they don't prevent cookie poisoning, which increases the security risks if there's ever a cross site scripting problem (or cross site scripting bug).

Effects of SECURE

The web server can use the Secure attribute to specify that the cookie should only be sent over an HTTPS connection, and only be accessible on a page served over HTTPS.

  Set-Cookie: test=helloworld; Secure;

In the example, the cookie test will not be sent to the server if an HTTP page is requested, nor will it be available in any client-side Javascript code on a page that is requested over HTTP.

The table shows for each brand of web browser if the cookie is used over HTTP when the Secure attribute was used when the cookie was set.

Cookie SecureWhen requesting URLSafari 4,
Safari 5,
Netscape 4,
Opera 12,
Chrome 28,
Internet Explorer 6,
Internet Explorer 7,
Internet Explorer 9,
Internet Explorer 10,
FireFox 12,
FireFox 23
Securehttp://mydomain.com/hello/world.htmnot sent
no DOM cookie
Securehttps://mydomain.com/hello/world.htmsent,
DOM cookie available

The next table shows what happens if the relevant cookie already exists and the server writes it again with the Secure attribute.

Cookie presentRequested pageSet-Cookie headerSafari 4,
Safari 5,
Netscape 4,
Opera 12,
Chrome 28,
Internet Explorer 6,
Internet Explorer 7,
Internet Explorer 9,
Internet Explorer 10,
FireFox 12,
FireFox 23
test=helloworld; https://mydomain.com/hello/world.htmtest=bye; Secure;Cookie is overridden
Cookie only used on HTTPS
test=helloworld; Secure;https://mydomain.com/hello/world.htmtest=bye;Cookie is overridden
Cookie on any protocol
test=helloworld; Secure;http://mydomain.com/hello/world.htmtest=bye;Cookie is overridden
Cookie on any protocol
test=helloworld; http://mydomain.com/hello/world.htmtest=bye; Secure;COOKIE IS OVERRIDDEN!
Cookie only used on HTTPS
test=helloworld; Secure;http://mydomain.com/hello/world.htmtest=bye; SecureCOOKIE IS OVERRIDDEN!
Cookie only used on HTTPS

Now you'd think that the browser wouldn't accept any cookies marked as Secure over an insecure connection, but as you can see, you'd be wrong. Every browser accepts secure cookies from an HTTP response.

In defense of the browser vendors: an HTTPS connection does not guarantee encryption, and if encryption is used, it doesn't guarantee encryption quality. So although it is certain that the data will be unencrypted over HTTP, there is no guarantee of any industry strength encrypting on HTTPS connections.

Please note that when a cookie is sent to the server, there is no indication of Secure (or HttpOnly) in the request, so the server will never know with what settings the cookie came about.

Exceptions

A HTTP response can have multiple Set-Cookie headers. However, it should only have a maximum of one header per combination of cookie name, domain and path. So what happens if the server does not comply with this specification?

  Set-Cookie: test=none;
  Set-Cookie: test=expires;  expires=Thu, 22-Jan-2015 00:00:10 GMT
  Set-Cookie: test=maxage; Max-Age=900

In the example, each of the three Set-Cookie headers is about the same cookie name/domain/path combination. In other words, they are each about the same cookie.

The table shows for each brand of web browser how it handles undefined situations.

Set-Cookie headersSafari 5,
Chrome 39,
Internet Explorer 11,
FireFox 34
Set-Cookie: test=none;
Set-Cookie: test=expires; expires=Thu, 22-Jan-2015 00:00:10 GMT
Last header is executed / value="expires"
Set-Cookie: test=expires; expires=Thu, 22-Jan-2015 00:00:10 GMT
Set-Cookie: test=maxage; Max-Age=900
Last header is executed / value="maxage"
Set-Cookie: test=maxage; Max-Age=900
Set-Cookie: test=none;
Last header is executed / value="none"
Set-Cookie: test=none;
Set-Cookie: test=httponly; HttpOnly;
Last header is executed / HttpOnly
Set-Cookie: test=httponly; HttpOnly;
Set-Cookie: test=secure; Secure;
Last header is executed / Secure
Set-Cookie: test=secure; Secure;
Set-Cookie: test=none
Last header is executed / value="none"
Set-Cookie: test=none
Set-Cookie: test=expired; expires=Thu, 01-Jan-1970 00:00:10 GMT
Last header is executed / cookie removed

So no surprises here.

To be continued, with topics like how 3rd party cookies are handled, etc.

Mail your comments to gertjans@xs4all.nl.