socket.io sets cross-site cookie without same-site attribute - npm

I have a socket.io application and recently I got this warning:
A cookie associated with a cross-site resource at URL was set
without the SameSite attribute.
A future release of Chrome will only deliver cookies with cross-site requests if they are set with SameSite=None and Secure.
You can review cookies in developer tools under
Application>Storage>Cookies and see more details at
https://www.chromestatus.com/feature/5088147346030592 and
https://www.chromestatus.com/feature/5633521622188032.`
Apparently it is something that Chrome will be updating in the future:
SameSite warning Chrome 77
I already tried this but to no apparent avail : io = io.listen(server, { cookie: false });
I think the cookie doesn't do anything, so how can I disable io from setting it?

As per the issue reported in Socket IOs' github repo, that cookie is not used for anything; you can disable it by setting cookie: false in the server options.
But what you have missed is setting {cookie: false} option when initializing the socket, not http.listen. The solution provided below worked for me that uses express as the server.
var server = require('http').createServer(express());
var io = require('socket.io')(server, { path:"/some/path", cookie: false });

Related

Problem with setting cookies on localhost during development

I have nodejs express app as backend, and vue app as frontend on my server. I use session cookies for authentication and i just can't get them working on my local dev machine. Cookie is sent in the response but it is not saved by browser. I know that problem is that request origin must be same as host and i have read all the articles/questions related to the issue and i just can't solve it.
On the server, everything is proxied with nginx on https. Cookie is set there and everything works fine, because they are on same host.
My local vite dev server is running on https, on port 5173.
I use axios for api calls and i have set
axios.defaults.withCredentials = true;
Cookie properties are
sameSite:'none',
secure:true,
httpOnly:true,
In express:
app.use(
cors({
origin: ['https://localhost:5173', 'https://my.site.com'],
credentials: true,
})
);
Like i said before, cookie is sent in the response from the server and just not stored on browser because in request header:
host:my.site.com
origin:https://localhost:5173
referer:https://localhost:5173/
How can i solve this?
I followed solution in comments on https://stackoverflow.com/a/46412839/13781306.
It partialy works when i set
sameSite:'none',
secure:false,
Cookie is passed in requests but it is not stored in the browser storage/cookies. Which is fine and solves my issue.

Is it possible to set an HttpOnly Cookie from one domain to another subdomain

I originally posted this question here: https://security.stackexchange.com/questions/255737/is-it-possible-to-set-an-httponly-cookie-from-one-domain-to-another-subdomain
Please keep in mind that this question is specific to cookies with the HttpOnly flag set to true.
I am pretty sure that the answer to my question is no, but I have been have a hard time finding an answer through official documentation or other posts here. Here is simple use case for some context:
Python backend web application (api.domain.com)
Frontend JavaScript SPA (app.domain.com)
post requests to api.domain.com/api/auth/login/ made from app.domain.com using axios with the correct username and password return a response with an access JWT token in the body and the response sets a refresh cookie with an HttpOnly flag [should fail, since I believe that the cookie cannot be set on app.domain.com from an API request to api.domain.com? -- this is my question]
the access token is stored in memory and passed with each API request
requests made to api.domain.com/api/auth/refresh/ are sent on a schedule to refresh the short-lived access token.
I typically host the frontend app and backend app on the same subdomain (app.domain.com) and do path-based routing with something like CloudFront or nginx, and this works well. For example, all requests starting with /api/* are sent to the backend, and all other requests are sent to the frontend app. Trying to use a separate subdomain for the API seems to fail no matter what options I use for setting the cookie on the server.
Can someone help me confirm that it is in fact not possible to set an HttpOnly cookie on a subdomain like app.domain.com from an API request hosted on api.domain.com? It would be great if anyone can also help me find where this could possibly be found in official documentation.
Searching for set httpOnly cookie across subdomains, I haven't found anything directly relevant. I also didn't find anything in these resources that directly answers my question:
https://owasp.org/www-community/HttpOnly
https://learn.microsoft.com/en-us/previous-versions//ms533046(v=vs.85)?redirectedfrom=MSDN
This is possible. In fact I just did it.
On your frontend, using Axios:
const baseURL = 'https://api.example.com';
const api = axios.create({
baseURL,
withCredentials: true,
});
On your backend, using Express:
app.use(
cors({
origin: 'https://www.example.com',
credentials: true,
}),
);
app.post('/login', async (req, res) => {
res.cookie('someCookie', someCookieValue, {
secure: true,
domain: 'example.com',
httpOnly: true,
});
});

Navigator.sendBeacon not working with Authorization Headers

Recently chrome stop support for synchronos xmlhttprequest on page unload or beforeunload event https://www.chromestatus.com/feature/4664843055398912
i try this solution Perform an asynchronous service get when closing browser window / tab with Angular but not seems to be working in latest chrome versions
Now i am using navigator.sendbeacon api like this
let headers = {
type: 'application/json; charset=utf-8',
'authorization': `bearer ${token}`
}
let blob = new blob([json.stringify({a:"9"})], headers);
navigator.sendbeacon(uri, blob);
Api is throwing 401 so seems like authorization is not working,
Is there any other alternative to navigator.sendBeacon
At time of this writing, no. Chrome (and probably other browsers too more sooner than later) will disallow XHR-sync because of bad UX to the user (the browser hangs if user is closing the tab and an XHR-sync request is made).
There are a few workarounds though, but each have their drawbacks as well
Use the new (and experimental) sendBeacon API - sendBeacon simply "queues" the request and this guarantees that the request will be fired even on page unload. That too without blocking the UX. Some limitations with this are that you cannot change request headers by default. If you DO need to add custom headers, you will have to use a blob, and that too the headers should be CORS-friendly. And will not work on older browsers (looking at you, IE)
Use fetch() API + keepalive flag - but this again works if you request headers are on the CORS-safelist. Basically if your fetch() request has certain request headers, then a preflight request can be made for security reasons. If such a preflight request is made, then the fetch() + keepalive is disallowed by some browsers. Basically you need to keep your request simple for this to work. For example, Such as you cannot use a content-type=application/json here. One workaround for this is to send data as text/plain and get your server to handle it accordingly.
Some more info on CORS simple vs preflight requests can be found here.
Chrome does allow a temporary workaround but this will work only till Oct 2020. More info on that here.

Strategy for CORS - issue with IE10 : xhr status returns 0 for HTTP 401

I have the following setup on my server:
Apache HTTP Server is serving a BackboneJS frontend application
Apache Tomcat is serving a Java based backend (CORS enabled).
Everything is running on a single server that I have full control over.
I'm currently using com.thetransactioncompany.cors.CORSFilter in the Java based backend to enable CORS. Everything seens to be working fine.
My frontend has the following code to redirect the user to the login page in case an un-authenticated REST call occurred:
$.ajaxSetup({
statusCode: {
401: function(){
window.location.replace('/#login');
},
403: function() {
window.location.replace('/#denied');
}
},
cache: false
});
Everything works fine on all major browsers except for IE10.
In IE10, when the non-authenticated users calls the REST serverm the server returns an HTTP 401 (as it should). The XHR object I'm seeing in the IE debugger hoewever seems to have translated this into status = 0. (On chrome you can cleary see that it has status = 401.
This appears to be a bug in IE10 where IE10 is treating HTTP status 401 as a network error. The console shows:
SCRIPT7002: XMLHttpRequest: Network Error 0x80070005, Access is denied
Is there a way to workaround this ?
I can add handling for statusCode 0 in the ajaxSetup but that seems more of a hack.
Is there a way to disable CORS altogether through some kind of Apache / Tomcat configuration ?
Currently my apache configuration is setup using vhosts so that the following public URLs map their corresponding internal hostname / ports.
http://mywebapp.com -> http://myrealservername:8080/ -> /var/www/http
http://myrestapi.com -> http://myrealservername:8088/ -> /usr/local/tomcat/webapps/restapi
Would it be possible / advisable to have Apache
continue serving the static webapp from http://mywebapp.com/restapi
exposing the REST API on http://mywebapp.com/restapi (keeping it "inside" the webapp).
If such a setup were possible I wouldn't need CORS anymore ? It would keep things a lot simpler while increasing browser support ?

Using stomp.js over sock.js with ActiveMQ-Apollo does not seem to work

I am working through some samples in the ActiveMQ-Apollo installation and playing around with the examples/websocket.
In this file, Stomp.js is being used to establish connection:
client = Stomp.client(url);
The example works fine and I am able to see the messages being sent and received. The issue, is that Stomp uses default WebSocket which may not be available at times. So, I wanted to integrate with SockJS client library. According to the example for StompJS on this page (http://jmesnil.net/stomp-websocket/doc/) it should be possible with this code:
<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<script>
// use SockJS implementation instead of the browser's native implementation
var ws = new SockJS(url);
var client = Stomp.over(ws);
[...]
</script>
The above code appears to execute correctly, however, later I see the following errors:
XMLHttpRequest cannot load ws://mylocaldomain.com:61623/info. Cross origin requests are only supported for HTTP. sockjs-0.3.js:807
Uncaught Error: NetworkError: DOM Exception 19
Then, I see the debug window show this message:
Opening Web Socket...
Whoops! Lost connection to undefined
I am serving the page from mylocaldomain.com:80, and the ActiveMQ Apollo server is running on the same machine, but listening on port 61623. I have also grabbed the latest version of StompJS (from dist directory on github) as well as SockJS directly from cdn.sockjs.org.
I tried this example on latest Chrome and Firefox (on OSX) and the same thing occurs. No connection is established.
Again, going back to the standard example which ships with the Apollo works fine, but I would like to find out why StompJS over StockJS is failing.
Has anyone seen this issue?
Thanks.
-AP_
You need to modify the ActiveMQ-Apollo web configuration to support Cross-Origin-Resource-Sharing (CORS) as described here:
Enabling CORS
W3C CORS Specification
Basically the server needs to do the following things:
Support the HTTP OPTIONS request (aka CORS pre-flight request) that is sent by browsers for Cross Domain requests. This includes responding to the OPTIONS request with:
Access-Control-Allow-Origin header (for example: "*" which means allow all origins)
Access-Control-Request-Method header (for example: "GET, POST, PUT, DELETE, OPTIONS")
Access-Control-Allow-Headers (for example: "X-Requested-With,Origin,Content-Type, Accept")
The handling of HTTP OPTIONS can typically be done using a single Web Filter matching filter pattern "/*".
See also "cors_origin" WebSocket connector URL query parameter supported by ActiveMQ Apollo 1.7