I have two questions. I understand that if I specify the domain as .mydomain.com
(with the leading dot) in the cookie that all subdomains can share a cookie.
The 2 domains mydomain.com
and subdomain.mydomain.com
can only share cookies if the domain is explicitly named in the Set-Cookie
header. Otherwise, the scope of the cookie is restricted to the request host. (This is referred to as a "host-only cookie". See What is a host only cookie?)
For instance, if you sent the following header from subdomain.mydomain.com
, then the cookie won't be sent for requests to mydomain.com
:
Set-Cookie: name=value
However if you use the following, it will be usable on both domains:
Set-Cookie: name=value; domain=mydomain.com
This cookie will be sent for any subdomain of mydomain.com, including nested subdomains like subsub.subdomain.mydomain.com
.
In RFC 2109, a domain without a leading dot meant that it could not be used on subdomains, and only a leading dot (.mydomain.com
) would allow it to be used across multiple subdomains (but not the top-level domain, so what you ask was not possible in the older spec).
However, all modern browsers respect the newer specification RFC 6265, and will ignore any leading dot, meaning you can use the cookie on subdomains as well as the top-level domain.
In summary, if you set a cookie like the second example above from mydomain.com
, it would be accessible by subdomain.mydomain.com
, and vice versa. This can also be used to allow sub1.mydomain.com
and sub2.mydomain.com
to share cookies.
See also:
Here is an example using the DOM cookie API (https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie), so we can see for ourselves the behavior.
If we execute the following JavaScript:
document.cookie = "key=value"
It appears to be the same as executing:
document.cookie = "key=value;domain=mydomain.com"
The cookie key becomes available (only) on the domain mydomain.com.
Now, if you execute the following JavaScript on mydomain.com:
document.cookie = "key=value;domain=.mydomain.com"
The cookie key becomes available to mydomain.com as well as subdomain.mydomain.com.
Finally, if you were to try and execute the following on subdomain.mydomain.com:
document.cookie = "key=value;domain=.mydomain.com"
Does the cookie key become available to subdomain.mydomain.com? I was a bit surprised that this is allowed; I had assumed it would be a security violation for a subdomain to be able to set a cookie on a parent domain.
In both cases yes it can, and this is the default behaviour for both IE and Edge.
The other answers add valuable insight but chiefly describe the behaviour in Chrome. it's important to note that the behaviour is completely different in IE. CMBuckley's very helpful test script demonstrates that in (say) Chrome, the cookies are not shared between root and subdomains when no domain is specified. However the same test in IE shows that they are shared. This IE case is closer to the take-home description in CMBuckley's www-or-not-www link. I know this to be the case because we have a system that used different servicestack cookies on both the root and subdomain. It all worked fine until someone accessed it in IE and the two systems fought over whose session cookie would win until we blew up the cache.
Please everyone note that you can set a cookie from a subdomain on a domain.
(sent in the response for requesting subdomain.mydomain.com
)
Set-Cookie: name=value; Domain=mydomain.com // GOOD
But you CAN'T set a cookie from a domain on a subdomain.
(sent in the response for requesting mydomain.com
)
Set-Cookie: name=value; Domain=subdomain.mydomain.com // Browser rejects cookie
According to the specifications RFC 6265 section 5.3.6 Storage Model
If the canonicalized request-host does not domain-match the domain-attribute: Ignore the cookie entirely and abort these steps.
and RFC 6265 section 5.1.3 Domain Matching
Domain Matching
A string domain-matches a given domain string if at least one of the following conditions hold:
The domain string and the string are identical. (Note that both the domain string and the string will have been canonicalized to lower case at this point.)
All of the following conditions hold:
The domain string is a suffix of the string.
The last character of the string that is not included in the domain string is a %x2E (".") character.
The string is a host name (i.e., not an IP address).
So "subdomain.mydomain.com" domain-matches "mydomain.com", but "mydomain.com" does NOT domain-match "subdomain.mydomain.com"
Check this answer also.
Simple solution
setcookie("NAME", "VALUE", time()+3600, '/', EXAMPLE.COM);
Setcookie's 5th parameter determines the (sub)domains that the cookie is available to. Setting it to (EXAMPLE.COM) makes it available to any subdomain (eg: SUBDOMAIN.EXAMPLE.COM )
Reference: http://php.net/manual/en/function.setcookie.php
I'm not sure @cmbuckley answer is showing the full picture. What I read is:
Unless the cookie's attributes indicate otherwise, the cookie is returned only to the origin server (and not, for example, to any subdomains), and it expires at the end of the current session (as defined by the user agent). User agents ignore unrecognized cookie.
RFC 6265
Also
8.6. Weak Integrity
Cookies do not provide integrity guarantees for sibling domains (and
their subdomains). For example, consider foo.example.com and
bar.example.com. The foo.example.com server can set a cookie with a
Domain attribute of "example.com" (possibly overwriting an existing
"example.com" cookie set by bar.example.com), and the user agent will
include that cookie in HTTP requests to bar.example.com. In the
worst case, bar.example.com will be unable to distinguish this cookie
from a cookie it set itself. The foo.example.com server might be
able to leverage this ability to mount an attack against
bar.example.com.
To me that means you can protect cookies from being read by subdomain/domain but cannot prevent writing cookies to the other domains. So somebody may rewrite your site cookies by controlling another subdomain visited by the same browser. Which might not be a big concern.
Awesome cookies test site provided by @cmbuckley /for those that missed it in his answer like me; worth scrolling up and upvoting/: