> draft
Zhong Yu, 2015-06-05
This article explains HTTP cookie domain policy, based on RFC_6265 and current browser behaviors.
A website can set a cookie in a response; the cookie will be sent back to the same website in subsequent requests.
More precisely, if an HTTP client issues a request to a domain, and the response contains a valid cookie, the client should apply the cookie to subsequent requests to the same domain (subject to other constraints). We say the request domain is the origin domain of the cookie. A cookie is always applicable to its origin domain.
For example, cookie foo=bar
originated from www.cats.com
is applied to later requests to the same domain -
request#0 GET http://www.cats.com:8080/abc HTTP/1.1 response#0 HTTP/1.1 200 OK Set-Cookie: foo=bar; Path=/; Expires=Sun, 02 Feb 2020 00:00:00 GMT ... request#n GET https://www.cats.com/xyz HTTP/1.1 Cookie: foo=bar
Note that the port number doesn't matter here; the scheme(http/https
) doesn't matter either (unless cookie's Secure
attribute is set). In the example above, the cookie originated from http://www.cats.com:8080
is applicable to request to https://www.cats.com:443
as well, even though the schemes and ports are different.
If the request host is an IP address, e.g. 127.0.0.1
, we say, for the purpose of this article, that the origin domain is the IP.
A cookie can have the "Domain" attribute set to a valid domain name, which we call the cover domain of the cookie. If the "Domain" attribute is not set, we say the cover domain is null.
If cover domain is null, a cookie is only applicable to its origin domain. For example, a cookie from www.cats.com
is not applicable to cats.com
, and vice versa, if cover domain is null.
If cover domain is set, a cookie is applicable to the cover domain and all its subdomains. For example
request#0 GET http://foo.www.cats.com/ HTTP/1.1 response#0 HTTP/1.1 200 OK Set-Cookie: foo=bar; Path=/; Domain=cats.com
the cover domain is cats.com
, therefore the cookie is applicable to cats.com
, x.cats.com
, x.y.cats.com
, etc.
The cover domain must cover the origin domain, that is, the cover domain must be the same as, or a parent of, the origin domain. In the example above, the origin domain is foo.www.cats.com
, therefore the cover domain could only be set to foo.www.cats.com
, www.cats.com
, or cats.com
(but not "com"
, see next section).
If the origin domain is an IP, the cover domain must be null. A cookie with an IP origin is only applicable to that IP.
A cover domain should not contain a leading dot, like in .cats.com
; if it does, the client should remove the leading dot.
If a cookie's cover domain is set illegally or incorrectly, the client should ignore the cookie entirely.
On a related matter, a cookie's identity is defined by the triplet (name, domain, path)
, of which domain
is either the cover domain if it's set, or the origin domain otherwise. This needs to be noted when replacing or deleting a cookie.
Obviously, we cannot allow a cover domain to be "com"
, otherwise, a cookie from cats.com
could be sent to dogs.com
, causing problems. A cover domain must not be a public suffix.
A public suffix is a domain under which the general public can register direct subdomains. For example, "com"
, "org"
, "uk"
, "co.uk"
are public suffixes. Direct subdomains of a public suffix belong to different owners, therefore their cookies should not mingle, and that's why a public suffix cannot be allowed as cover domain.
A private company can also offer a domain as a public suffix. For example, when you lease a server from Amazon AWS, a domain name is assigned to it, e.g. foo.compute.amazonaws.com
. You "own" this domain in the sense that its usage is at your discretion. Someone else may own a sibling bar.compute.amazonaws.com
. To prevent bar
from sending cookies to foo
, the domain compute.amazonaws.com
is listed as a public suffix.
The complete list of public suffixes is maintained at https://publicsuffix.org. In addition, we recommend that
As far as cookie handling is concerned, every TLD is a public suffix, even if it's not listed. For example, "test"
, "local"
, "my-fake-tld"
, etc. cannot be allowed as cover domains.
As far as cookie handling is concerned, parents of a public suffix are public suffixes too, even if they are not listed. For example, amazonaws.com
is not listed as a public suffix, yet it cannot be allowed as cover domain either, because it is the parent of public suffix compute.amazonaws.com
.
These two bullet points cannot be derived from the texts of RFC_6265 and publicsuffix.org; instead, they are concluded from current behaviors of major browsers. Other client and server implementers should follow these behaviors too. It's a simplified and conservative approach for dealing with subtleties of public suffix. See next section for a more complicated narrative.
Summary of rules from above:
According to RFC_6265, if a cookie's cover domain is a public suffix,
The first clause looks odd, but it permits a public suffix domain (if it ever resolves to an HTTP server) to specify itself as the cover domain, while making sure the cookie will not propagate to subdomains. Presumably, this clause is for backward compatibility of some existing websites on public suffix domains. However, the only major browser that currently implements this clause is Firefox; all other major browsers simply reject such cookies. Therefore in the previous section, to follow the browser consensus, we reject this case as well - a cover domain cannot be a public suffix, regardless of the origin domain.
Another problem - RFC_6265 does not properly handle the situation where a public suffix has a parent that is not a public suffix; such situation probably didn't exist when the RFC was written. Strictly following the texts of the RFC, a client would allow foo.compute.amazonaws.com
to set a cookie's cover domain to amazonaws.com
, and the cookie would be applicable to bar.compute.amazonaws.com
. This behavior is clearly undesired.
Fortunately, no major browser behaves that way; however, browsers handle the case differently. Safari appears to simply treat amazonaws.com
as a public suffix, rejecting all cookies with it as cover domain. In the previous section, we follow this simple approach, rejecting any parent of public suffix as cover domain.
On the other hand, Firefox and Chrome take a more sophisticated approach, allowing amazonaws.com
as cover domain in some cases (e.g. when the origin domain is www.amazonaws.com
) while making sure those cookies do not propagate below compute.amazonaws.com
. This approach is better; however, Amazon cannot really rely on it to share cookies, because not all browsers support the approach.
These discussions intend to justify the conservative approach we laid out in the previous section.
Nevertheless, it would be interesting to discuss what is the "ideal" way to handle public suffixes in cookie handling -
The domain amazonaws.com
is not really a public suffix, because its direct subdomains are not open to the public; instead, they are all controlled by Amazon. It doesn't really hurt if www.amazonaws.com
and zzz.amazonaws.com
, or even compute.amazonaws.com
, share cookies though domain amazonaws.com
- as long as these cookies do not propagate downwards across public suffix compute.amazonaws.com
, reaching user websites. At the same time, we must not allow a user website under compute.amazonaws.com
to set a cover domain to amazonaws.com
, interfering with Amazon's websites.
With that in mind, the next section defines a more sensible model for cookie domain policy.
A cover domain's coverage is the set of domains that the cookie is applicable to; the set is defined by:
That is, the coverage starts from the domain, propagates downwards, stopped at public suffix nodes.
The coverage is tested when receiving and sending the cookie, in a symmetric way
Return to the Amazon example,
compute.amazonaws.com
only covers itself, since it's a public suffix.amazonaws.com
covers amazonaws.com
, www.amazonaws.com
, foo.www.amazonaws.com
, and compute.amazonaws.com
; it does not cover foo.compute.amazonaws.com
.Here's a pseudo code for getting the list
of cover domains that cover a given request_domain
list.add(request_domain) for each parent of request_domain, ordered from longest to shortest if parent is a public suffix break loop list.add(parent)
Contact: bayou-io@googlegroups.com