This really annoying, partly because its internal to chrome and its more or less a guessing name. But my request header is not passing along the cookies for the same domain.
I have a cookie with a domain set to
.domain.net
My application is at the following URL
myapp.foo.bar.domain.net
I'm trying to send a request to another server on the same root domain at
otherapp.bar.domain.net
The cookie does not send in Chrome but does send in Safari.
According to the HTTP cookie spec, it should send because ".domain.net" is the master domain both both .bar.domain.net and .foo.bar.domain.net
Furthermore, I know the domain level cookie is working because when I make a GET request to myapp.foo.bar.domain.net or to myapp.bar.domain.net, the cookie is indeed passed in the header. It seems to fail in the case when I'm making a request to either domain when the origin is the other.
Does anyone know if this is a known bug in Chrome, I'm running version 59.
Turns out I was not adding
xhrFields: {
withCredentials: true
},
In the ajax request. This was a little confusing because this was all working before I changed the domain and whats more confusing is that this works with Safari without needing to set that withCredentials header. The take away here is that Chrome will not send cookies if the hostname differs, even when a root domain cookie is set, unless the withCredentials header param is passed, however Safari will send no matter what. I don't know about Firefox.
Related
I'm running an application on http://localhost:3000 and I am successfully receiving a response with the two cookies shown below on my network tab in Chrome.
However, these cookies are not being set. I'm wondering if maybe I have incorrectly set certain attributes on the cookies, and that's why they aren't being saved?
If I go to the Application tab and refresh and view my cookies
We can see that the above cookies are not there.
The request I'm making is just a simple asynchronous axios.post(http://localhost:5000, data).
How can I get these cookies to be stored correctly?
I needed to add withCredential: true like so:
axios.post(http://localhost:5000, data, {withCredentials: true})
Recently browsers are increasing security to prevent CSRF attacks via enhancing samesite cookie default value to Lax, i.e., if the samesite attribute is not set by the server while setting cookie via response set-cookie header, browser will consider them as Lax, and not stored, so in the subsequent calls the cookies are not sent back to server failing those requests. This happens on cross domain communication where a cross domain application is running in an iFrame on the main website.
We have one such server application that sets two cookies on the response of successful authentication requests, and those cookies are supposed to be sent back to server with every subsequent call to make the server believe the requests are authenticated for further processing. These cookies don't have any samesite attribute set explicitly, so the new browsers (Chrome 80) is not sending them back in the subsequent calls.
The server application is hosted on tomcat. So in order to mitigate the issue we used tomcat's cookieprocessor to set the cookie's samesite attribute to be set as "none", so that cross domain calls cane be made. Unfortunately that did not work. Despite setting samesite attribute explicitly via cookieprocessor that response while checked via developer tools does not show any trace of samesite attribute.
So here the question: am I getting it correct that tomcat should modify the server's response to add the samesite attribute to the cookies those are set via set-cookie header on the response? I tried debugging the cookieprocessor code by setting up remote debugging but it looks like the response's are not intercepted and hence the cookie header is getting modified. What I am doing wrong here?
Note: I have configured the cookieprocessor in application's meta-inf/context.xml.
So you're using Tomcat, but what version of Tomcat are you using?
The initial release of the CookieProcessor SameSite support used "None" to refer to behavior to unset the SameSite value.
https://bz.apache.org/bugzilla/show_bug.cgi?id=63865
Fixed in:
- master for 9.0.28 onwards
- 8.5.x for 8.5.48 onwards
I'm not sure if the CookieProcessor from Tomcat considers the User-Agents of the clients.
If you implement this way, your application may not support the known incompatible clients: Chrome 51-66, MacOSX Mojave (10.14) Safari/Embedded, iOS 12, UCBrowser prior to 12.13.2
https://www.chromium.org/updates/same-site/incompatible-clients
We solved our normal cookies by using addHeader to support SameSite.
We solved our session cookies in our nginx layer.
For JSESSIONID, it seems you could also use a Filter to wrap HttpServletRequest to append a copy of the session cookie with proper attributes whenever a new session is created. Though it is adding like ~80B for the overriding JSESSIONID.
I actually resolved the mystery by myself. Cookieprocessor works only if the cookies are added via response.addCookie() method. So, if the cookies are set via set/add header methods cookieporcessor won't do anything. Actually our server application does the header approach to add cookie and not the addCookie() method.
Chrome has a long history of ignoring Set-Cookie header. Some of these reasons have been termed bugs and fixed, others are persistent. None of them are easy to find in documentation.
Set-Cookie not allowed in 302 redirects
Set-Cookie not allowed if host is localhost
Set-Cookie not allowed if Expires is out of acceptable range
I am currently struggling with getting chrome to accept a simple session cookie. Firefox and Safari seem to accept most any RFC compliant string for Set-Cookie. Chrome stubbornly refuses to acknowledge that a Set-Cookie directive was even sent on the request (does not show up in Developer Tools (Network)). curl looks fine.
So does anyone have either 1) modern best practices for cross-browser Set-Cookie formatting or 2) more information regarding what can cause Chrome to bork here?
Thanks.
One thing that has bitten me and is not on your list: if you are trying to set a secure cookie through HTTP on localhost, Chrome will reject it because you are not using HTTPS.
This kind of makes sense, but is annoying for local development. (Firefox apparently makes an exception for this case and allow to set secure cookies over HTTP on localhost).
I work in a corporate environment and found an issue I can't resolve.
It has to do with EventSource changing the URL param from HTTP to HTTPS.
const url = 'http://localhost:8080'; // <-- using HTTP not HTTPS
new window.EventSource(url);
Which results in the browser throwing this error:
GET https://localhost:8080 net::ERR_TUNNEL_CONNECTION_FAILED
I am developing on a website using HTTPS so maybe this is by design that it uses the same protocol. Anyone experienced this issue or know how to resolve it?
--- Update ---
Looks like it is by design. When attempting this on another HTTPS site I got this:
Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure EventSource endpoint 'http://localhost...'. This request has been blocked; the content must be served over HTTPS.
The question still remains, how do I get around this?
Eventsource won't change between http and https. Are you using the HTTPS Everywhere plugin for Chrome, or something like that?
I think you are being hit by the same-origin policy. What this means is that the SSE connection must be to the same origin, which basically means the same hostname and domain, same scheme (i.e. either both http or both https) and same port.
You can use CORS to get around this. At the top of your SSE script you need to send back this header:
Access-Control-Allow-Origin: *
This says anyone, from anywhere, is allowed to connect and get the data stream. It has to be done on the server script, there is no way to do it from the client. (By design: the whole point of same-origin policy is to stop people using other people's content and making it look like their own, without permission.)
Shameless Plug: see my chapter 9 in my book (Data Push Apps with HTML5 SSE, O'Reilly) for finer control of allow-origin, and how it interacts with cookies and basic auth.
BTW, I notice I mention that Chrome won't work with self-signed https certificates. To be honest I'm not sure if that is still the case, but that might also be something to watch out for when using https and localhost.
I'm studing HTML5's security problems. I saw all the presentations made by Shreeraj Shah. I tried to simulate a basic CSRF attack with my own servers using withCredentials tag sets to true (so in the response message the cookies should be replayed) and adding Content-Type sets to text/plain in the request (to bypass the preflight call).
When I tried to start the attack the browser told me that the XMLHttpRequest can not be accomplish because of the Access-Control-Allow-Origin header. So I put a * in the header of the victim's web page and the browser told me that I can't use the * character when I send a request with withCredentials sets to true.
I tried to make the same thing with the web apps stored in the same domain, and all was fine (I suppose it is because the browser doesn't check if the request comes from the same domain).
I'm asking, it's a new features that modern browsers set up recently to avoid this kind of problems?
Because in the Shreeraj's videos, the request was across different domains and it worked...
Thank you all and sorry for my english :-)
EDIT:
I think I found the reason why the CSRF attack doesn't work fine as in the Shreeraj's presentations.
I read the previous CORS document, published in 2010, and I found that there wasn't any recommendation about the with credential flag setted to true when Access-Control-Allow-Origin is set to *, but if we look at the last two publications about CORS (2012 and 2013), in the section 6.1, one of the notes is that we can't make a request using with credentials flag setted to true if the Access-Control-Allow-Origin is set to *.
Here are the links:
The previous one (2010): http://www.w3.org/TR/2010/WD-cors-20100727/
The last two (2012, 2013): http://www.w3.org/TR/2012/WD-cors-20120403/ --- http://www.w3.org/TR/cors/
Here is the section I'm talking about: http://www.w3.org/TR/cors/#supports-credentials
If we look at the previous document we can not find it, because there isn't.
I think this is the reason why the simple CSRF attack made in 2012 by Shreeraj Shah today doesn't work (of course in modern browsers that follow the w3c's recommendations). Could it be?
The request will still be made despite the browser error (if there's no pre-flight).
The Access-Control-Allow-Origin simply allows access to the response from a different domain, it does not affect the actual HTTP request.
e.g. it would still be possible for evil.com to make a POST request to example.com/transferMoney even though there are no CORS headers set by example.com using AJAX.