Use document.cookie to create a cookie on a different subdomain [duplicate] - javascript

I have two questions. I understand that if I specify the domain as .example.com (with the leading dot) in the cookie that all subdomains can share a cookie.
Can subdomain.example.com access a cookie created in example.com (without the www subdomain)?
Can example.com (without the www subdomain) access the cookie if created in subdomain.example.com?

If you set a cookie like this:
Set-Cookie: name=value
then the cookie will only apply to the request domain, and will only be sent for requests to the exact same domain, not any other subdomains. (See What is a host only cookie?)
Two different domains (e.g. example.com and subdomain.example.com, or sub1.example.com and sub2.example.com) can only share cookies if the domain attribute is present in the header:
Set-Cookie: name=value; domain=example.com
The domain attribute must "domain-match" the request URL for it to be valid, which basically means it must be the request domain or a super-domain. So this applies for both examples in the question, as well as sharing between two separate subdomains.
This cookie would then be sent for any subdomain of example.com, including nested subdomains like subsub.subdomain.example.com. (Bear in mind there are other attributes that could restrict the scope of the cookie and when it gets sent by the browser, like path or Secure).
Because of the way the domain-matching works, if you want sub1.example.com and sub2.example.com to share cookies, then you'll also share them with sub3.example.com.
See also:
www vs no-www and cookies
setcookie.net: a site where you can try it out (disclaimer: developed by me, for this question)
A note on leading dots in domain attributes: In the early RFC 2109, only domains with a leading dot (domain=.example.com) could be used across subdomains. But this could not be shared with the top-level domain, so what you ask was not possible in the older spec.
However, the newer specification RFC 6265 ignores any leading dot, meaning you can use the cookie on subdomains as well as the top-level domain.

Please everyone note that you can set a cookie from a subdomain on a domain.
(sent in the response for requesting subdomain.example.com)
Set-Cookie: name=value; Domain=example.com // GOOD
But you can't set a cookie from a domain on a subdomain.
(sent in the response for requesting example.com)
Set-Cookie: name=value; Domain=subdomain.example.com // Browser rejects cookie
Why?
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.example.com domain-matches example.com, but example.com does not domain-match subdomain.example.com
Check this answer also.

I'm not sure cmbuckley's 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 and for those that missed it in his answer like me; worth scrolling up.
Cookie Test

Here is an example using the DOM cookie API, so we can see the behavior for ourselves.
If we execute the following JavaScript code,
document.cookie = "key=value"
it appears to be the same as executing:
document.cookie = "key=value;domain=example.com"
The cookie key becomes available (only) on the domain example.com.
Now, if you execute the following JavaScript code on example.com,
document.cookie = "key=value;domain=.example.com"
the cookie key becomes available to example.com as well as subdomain.example.com.
Finally, if you were to try and execute the following on subdomain.example.com,
document.cookie = "key=value;domain=.example.com"
does the cookie key become available to subdomain.example.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.

Be careful if you are working on localhost!
If you store your cookie in JavaScript like this:
document.cookie = "key=value;domain=localhost"
It might not be accessible to your subdomain, like sub.localhost. In order to solve this issue you need to use VirtualHost. For example, you can configure your virtual host with ServerName localhost.com, and then you will be able to store your cookie on your domain and subdomain like this:
document.cookie = "key=value;domain=localhost.com"

In both cases, yes, it can, and this is the default behaviour for both Internet Explorer and Edge.
The other answers add valuable insight, but they chiefly describe the behaviour in Chrome. It's important to note that the behaviour is completely different in Internet Explorer. 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 Internet Explorer shows that they are shared. This Internet Explorer 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 Internet Explorer and the two systems fought over whose session cookie would win until we blew up the cache.

I do this and it works for me:
Cookie.set('token', 'some jwt-token', { expire:50000, domain: 'example.com' })

Related

Difference in the domain while setting cookie using javascript document.cookie="domain=" v/s document.cookie="domain:"

When setting cookie in javascript using document.cookie="dom_x=yyy;domain=www.mozilla.org;path=/", the cookie gets set in the domain www.mozilla.org.
At the same time while using document.cookie="dom_x_dot=yyy;domain:www.mozilla.org;path=/" the cookies get set in the domain .www.mozilla.org.
Is the syntax document.cookie="dom_x_dot=yyy;domain:www.mozilla.org;path=/" valid and if so when does it need to be used?
When you set a cookie domain that starts with a dot, like '.www.mozilla.org', it will be sent to that domain but also all subdomains of that domain like 'sub.www.mozilla.org'. Without the dot it will only be send to the exact domain 'www.mozilla.org'.

Why some cookie cannot get from document.cookie?

I'm using document.cookie go get cookie value of website, but it cannot get all cookie values.
Example session cookie sid, I can see it in Google Chrome Cookie Manager, but cannot get value by javascript.
How I can set cookie by javascript but it does not display in document.cookie (still send these value to server in request header)?
Answer copied from github: https://github.com/expressjs/session/issues/274#issuecomment-185308426
Your cookie is likely set to httponly: true. This is the default value. If you, or anyone else reading this doesn't already know, it can be unnecessary and a bad decision to set this value to false.
Search for "httponly cookie" and you'll find some good explanations of why you wouldn't want Javascript to have access to cookies.
Also make sure that the cookie you are trying to access is in the scope of the document from where you are trying to access the cookie.
The Domain and Path directives define thescope of the cookie: what URLs the cookies should be sent to.
Domain specifies allowed hosts to receive the cookie. If unspecified, it defaults to the host of the current document location, excluding subdomains. If Domain is specified, then subdomains are always included.
For example, if Domain=mozilla.org is set, then cookies are included on subdomains like developer.mozilla.org.
Path indicates a URL path that must exist in the requested URL in order to send the Cookie header. The %x2F ("/") character is considered a directory separator, and subdirectories will match as well.
For example, if Path=/docs is set, these paths will match:
/docs
/docs/Web/
/docs/Web/HTTP
source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#Scope_of_cookies

Why does Chrome and Safari not see cookies for some sub-domains?

I have a site that's generating a cookie for example.com. It is accessible in Firefox, Chrome 18 and Safari at both http://example.com and http://www.example.com. However, I cannot access the cookie from http://test.me.example.com in webkit derived browsers. It works in Firefox.
I've tested this with domain= one of example.com and .example.com when setting the cookie from javascript.
The cookie has a path of / and has expires set.
How do you specify the subdomain?
Chrome expects cookies for subdomains to be prefixed with a dot
e.g. domain=.example.com
You may find this post useful: https://serverfault.com/questions/153409/can-subdomain-example-com-set-a-cookie-that-can-be-read-by-example-com
Quoting from the same RFC2109 you read:
* A Set-Cookie from request-host x.foo.com for Domain=.foo.com would
be accepted.
So subdomain.example.com can set a cookie for .example.com. So far so good.
The following rules apply to choosing applicable cookie-values from
among all the cookies the user agent has.
Domain Selection
The origin server's fully-qualified host name must domain-match
the Domain attribute of the cookie
So do we have a domain-match?
A is a FQDN string and has the form NB, where N is a non-empty name
string, B has the form .B', and B' is a FQDN string. (So, x.y.com
domain-matches .y.com but not y.com.)
But now example.com wouldn't domain-match .example.com according to the definition. But www.example.com (or any other "non-empty name" in the domain) > > would. This RFC is in theory obsoleted by RFC2965, which dictated things about forcing a leading dot for domains on Set-Cookie2 operations.
More important, as noted by #Tony, is the real world. For a glimpse into what actual user agents are doing, see
Firefox 3's nsCookieService.cpp
and
Chrome's cookie_monster.cc
For perspective into what actual sites are doing, try playing with wget using > --save-cookies, --load-cookies, and --debug to see what's going on.
You'll likely find that in fact most sites are using some combination of Set-> > Cookie from the older RFC spec with "Host" values, implicitly without a leading dot (as twitter.com does) or setting Domain values (with a leading dot) and redirecting to a server like www.example.com (as google.com does).

What should I know about cookies domain and scope for security purposes?

Where can I learn (or what is) about a cookie's scope to avoid CSRF and XSS attacks for authenticated users?
For example, if I have a multi-tenant system where a single user can be access to one or more sites what is more secure:
company1.hoster.com
company2.hoster.com
company3.hoster.com
or
www.hoster.com/company1
www.hoster.com/company2
www.hoster.com/company3
What happens if I set a cookie at "hoster.com"?
You can restrict the validity scope of cookie in the domain and the path separately. So you could set a cookie in both scenarios that is only valid for that specific domain/path combination:
To set a cookie for //company1.example.com/ only:
Set-Cookie: name=value; Path=/
Omitting the Domain attribute makes the cookie only valid for the domain that it was set in. And with Path=/ the cookie is valid for any path that has the prefix /.
To set a cookie for //example.com/company1/ only:
Set-Cookie: name=value; Path=/company1/
Same explanation as for the example above. The only restriction is that you need to use /company1/ instead of /company1 as Path=/company1 would be equivalent to Path=/ and thus would make the cookie also valid for /company2 and /company3.
And to avoid that the cookie can be read via JavaScript (reducing the assets accessible using XSS), set the HttpOnly attribute.
The Open Web application security project publishes lots of valuable information about secure web application development.
Cookie's have a scope and path attributes, you would normally not want ot issue cookies for "/" or wildcard hosts *.hoster.com would both be ill-advised.
It's not as simple as this one decision, it's good you thought of security in your design, but security is a process, in every phase of your development.

How does the browser / JavaScript same origin policy apply to two-level domain names?

I have some JavaScript that is sharing a request between two separate servers on the same domain.
Is .com a requirement for the domain in JavaScript?
In this case both the servers are on the .abc.tyy domain with the tyy being what would normally be .com
Wondering if I can only use .com for the domain? I am getting a permission denied error, but this code works fine on other separate servers on the same domain(.com).
Updated:
Here is exactly how I'm using this:
123.abc.tyy has a script that loads properties that I want to access.
The script on 123.abc.tyy at opening script tag, sets the document.domain to 'abc.tyy'.
When I call the 'getUser()' function in 123.abc.tyy's script FROM 234.abc.tyy I am getting a permission denied error.
The way I am calling 'getUser()' is:
I access http://123.abc.tyy in a browser, and the site allows me to specify a URL to load in one of it's frames. I point that URL to http://234.abc.tyy/BeginLoadPatient.aspx" in that page I am doing the following:
window.location = 'http://234.abc.tyy/LoadPatient.aspx?PatientId=' + getUser() '; with getUser being a function originating in 123.abc.tyy
If I add 234.abc.tyy and 123.abc.tyy to my trusted sites, everything works fine - is this skipping over the same origin policy?
No, the SOP doesn't care what the domain is, only that it represents the same origin. (Could it be that you have the .com domain hard-coded somewhere?)
Note that there's more than the domain to consider. The Same Origin Policy looks at protocol, port, and host as well. So aaa.abc.tyy and bbb.abc.tyy are different origins.
If you're in control of the servers involved, you might look at Cross-Origin Resource Sharing, but unfortunately CORS is only implemented in modern browsers (and on those versions of IE where it's supported, it's only supported if you use it explicitly).
Another option, of course, is JSON-P, which has the advantage of working cross-browser right now.
Another thing to look at is document.domain, details here and here.
Update after your edits:
The script on 123.abc.tyy at opening script tag, sets the document.domain to 'abc.tyy'.
When I call the 'getUser()' function in 123.abc.tyy's script FROM 234.abc.tyy I am getting a permission denied error.
You'll need to set document.domain to "abc.tyy" in BeginLoadPatient.aspx as well.
If I add 234.abc.tyy and 123.abc.tyy to my trusted sites, everything works fine - is this skipping over the same origin policy?
I wouldn't be at all surprised (although to me it would be pretty dodgy), but have no first-hand knowledge of it. Would be easy to test.

Categories