Let's say I have domain a.com and b.com, and I own both domains. There's a page on b.com called setcookie.aspx and in the server code, it sets a cookie under the b.com domain.
I want to make an HTTP get request to b.com/setcookie.aspx from a.com (b.com is already allowing CORS requests from a.com) like so:
$.get('http://www.b.com/setcookie.aspx');
For some reason, the cookie is not being set. However, if I put the URL in a hidden image tag:
<img src="http://www.b.com/setcookie.aspx" style="display: none;" />
Then it works. Any idea why the AJAX request doesn't set the cookie?
You need to make 2 changes.
On a.com
As pointed out by #Jaromanda X in the comments, you need to set withCredentials=true in your $.get request. Cross-domain cookies are not allowed to be set by browsers unless you do this. Read this XMLHttpRequest.withCredentials
On b.com
When a cookie is to be set from the server side, it will send a header of the form:
set-cookie: key=val; expires=Fri, 24-Jan-20 10:29:58 GMT; path=/; domain=example.com; HttpOnly; SameSite=Lax
Notice the SameSite=Lax flag. This prevents the browser from setting cookie across domains.
From the Mozilla Set-Cookie docs
Asserts that a cookie must not be sent with cross-origin requests,
providing some protection against cross-site request forgery attacks
You need to disable this flag. This will depend on your backend platform. I use Django and for me it was just changing 1 setting SESSION_COOKIE_SAMESITE. This allows me to set the session id cookie to be set via a cross-domain AJAX request.
Once you do these 2 changes, the cross-domain cookie will be set. However, make sure to have enough CORS and CSRF checks to ensure the request comes from trusted origins.
Related
I have a domain with multiple subdomains and for each subdomain, there is a session cookie set from the main domain. All the session cookies are set with the domain as ".mainDomain.com" and used in specific auth related api calls. Also I have cookies specific for each subdomain with domain set as "subdomain.mainDomain.com".
I want to send fetch calls with only the cookies set from the subdomain and not the main domain.
Is there any way to achieve this?
Or, if there is a way to send a set of handpicked cookies in request header while ignoring the browser cookies like
Header: { Cookie: "test=test;" // this doesn't work now }
I know if the domain is .mainDomain.com, then *.mainDomain.com and mainDomain.com can access it. I was wondering if there is any way to make fetch ignore this.
I tried to set the cookie in header for the fetch call, but since Cookie is a forbidden header name it is not working, obviously. The only way I can think of is remove the cookies from mainDomain before each api call and set it back after. But I don't want to do it.
Here is my scenario:
I am making an ajax request from foo.com to api.bar.com. In the response, it sets some cookies using Set-Cookie header. The domain on the set-cookie header is .bar.com. I am using all steps listed here How to make XMLHttpRequest cross-domain withCredentials, HTTP Authorization (CORS)?
I am able to see and verify (using Chrome extension EditThisCookie) that cookies are being set properly for domain .bar.com.
According to my understanding, when I make an ajax request (using withCredential:true) to cdn.bar.com, , it should include the cookies that were set earlier for domain .bar.com.
These cookies do not get included in the request, I can see it in fiddler. What am I missing here?
EDIT
Cookies DO get included in the request header If I make a request to cdn.bar.com from an origin app.bar.com. The problem only appears when it's called from a different origin foo.com.
The issue was with the SameSite restriction of the cookie. If I change the it from lax to No Restriction then it works fine.
When I send a response from my server after authentication, I'm setting an authentication token cookie in the client's browser using this header:
Set-Cookie:mysite_auth=encodedJwtHere.JustPretend; SameSite=lax; domain=subdomain.mydomain.com; HTTPOnly; Max-Age=600; Secure; path=/
However, when I open EditThisCookie in Chrome, I can see that the domain is being set to .subdomain.mydomain.com automatically.
From what I thought I understood, this shouldn't be an issue. When I request https://subdomain.mydomain.com in the browser, the cookie is being sent.
My issue happens when I try to make a CORS request. I'm developing a javascript app and serving it on localhost. When I make an AJAX call to https://subdomain.mydomain.com, the cookie is not sent.
I have all of the proper headers set on the response:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Content-Type, *
Access-Control-Allow-Origin:*
I have the {withCredentials:true} config on my request.
If I open https://subdomain.mydomain.com in the browser, then with EditThisCookie, I remove the prefix dot, I.E. I change .subdomain.mydomain.com to subdomain.mydomain.com, suddenly my AJAX calls from localhost work. The cookie is sent with the request.
So my question is, first of all, why is the cookie not being sent when there is a prefix dot, and is there a way to resolve this issue without manually editing the domain every time my cookie is refreshed?
If you're sending credentials, you can't respond with Access-Control-Allow-Origin:* - you must respond with a value that EXACTLY mirrors the Origin request header, e.g. Access-Control-Allow-Origin: {value-of-Origin-Header}.
In your case, that would presumably be Access-Control-Allow-Origin: https://subdomain.mydomain.com. Best not to hard-code it though - just mirror back Origin value.
I am trying to make connection with an API. When I call a method to this API, it respond with a cookie value sent via HTTP headers.
Will this header be automatically added to the client "my browser?" or do I have to parse the request first and create a cookie using setCookie?
if it does not add the cookies automatically, is there a way to do so?
It'll be handled automatically by your http client (you don't need to set it manually).
Server should respond with Set-Cookie header (not with cookie), then client will save that cookie, and send it on next requests.
Setting a cookie
Cookies are set using the HTTP Set-Cookie header, sent in an HTTP response. This header instructs the browser to store the cookie and send it back in future requests to the server (the browser will, of course, ignore this header if it does not support cookies or has disabled cookies).
As an example, the browser sends its first request to the homepage of the www.example.org website:
GET /index.html HTTP/1.1
Host: www.example.org
...
The server responds with two Set-Cookie headers:
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: theme=light
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
...
The server's HTTP response contains the contents of the website's homepage. But it also instructs the browser to set two cookies. The first, "theme", is considered to be a "session" cookie, since it does not have an Expires or Max-Age attribute. Session cookies are typically deleted by the browser when the browser closes. The second, "sessionToken" contains an "Expires" attribute, which instructs the browser to delete the cookie at a specific date and time.
Next, the browser sends another request to visit the spec.html page on the website. This request contains a Cookie header, which contains the two cookies that the server instructed the browser to set.
GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: theme=light; sessionToken=abc123
...
This way, the server knows that this request is related to the previous one. The server would answer by sending the requested page, and possibly adding other cookies as well using the Set-Cookie header.
The value of a cookie can be modified by the server by including a Set-Cookie header in response to a page request. The browser then replaces the old value with the new value.
The value of a cookie may consist of any printable ASCII character (! through ~, unicode \u0021through \u007E) excluding , and ; and excluding whitespace. The name of a cookie excludes the same characters, as well as =, since that is the delimiter between the name and value. The cookie standard RFC 2965 is more limiting but not implemented by browsers.
The term "cookie crumb" is sometimes used to refer to a cookie's name-value pair.
Cookies can also be set by scripting languages such as JavaScript that run within the browser. In JavaScript, the object document.cookie is used for this purpose. For example, the instruction document.cookie = "temperature=20" creates a cookie of name "temperature" and value "20".
See wikipedia page
Yes, the cookie will be added to document.cookie, unless the httponly param is set when sending the cookie.
I was working on jsonP to send data from a cookie, from a domain A to a domain B. It works well, but my question is not here. I just realize that if I only put a script tag on my domain B pointing to my domain A, all the cookies of my domain A are set on my domain B.
Example: I put this tag on my domain B :
<script src="http://mydomainA.com/"></script>
Only with that, all the cookies of my domain A are set on my domain B.
My question is, is it normal? I thought cookie need some hacks to be cross domain, but i didn't think it was that easy.
Sorry for my bad english, and apologize if my question is stupid or if it has been asked before.
Thanks in advance.
Cookies are simply headers in HTTP requests. When the browser requests
GET /foo
Host: a.com
it receives a HTML document, which contains a <script> tag hosted on another domain. So it fires another request:
GET /script.js
Host: b.com
Cookie: foobarbaz
and it can certainly append cookies for domain b.com, if any. This means that the last time the browser contacted b.com, the HTTP response contained an header like
...
Set-Cookie: foobarbaz
...
and so subsequent requests to the same domain will maintain the session. When the browser requests another resource to a.com such as
GET /bar.jpeg
Host: a.com
the cookie foobarbaz set by b.com will not be sent along with the request, so the scripts on a.com don't have access to data from b.com.