Is it impossible to pass cookie cross domain with WebSocket handshake? - javascript

Context:
I'm developing a frontend app locally, calling APIs etc cross-domain (from localhost dev server to our server on another machine inside the local network). Since our local network is isolated, the backend server has CORS enabled which doesn't cause security problems; this is different in production (CORS is disabled).
We introduced WebSocket connections in our app and to secure it with authorization we added cookie check on handshake. (XHR requests are authorized via the Authorization header, cookies are not used there; but they actually can be used; WebSocket interface only allows a limited set of headers and if we don't authorize via WS messages, cookies seem to be the only sane option; well, in fact I failed to find if Basic HTTP auth can be implemented without broswer standart prompt, and how to do that)
The problem:
while this actually works for production (when frontend and backend are on the same domain), and cookies are sent in the handshake request inside the Cookie header (the code is trivial: I just set the cookie after getting the auth token), this doesn't work in development environment (localhost + backend on another domain): the Cookie header is just absent in the handshake. The link above shows that XHR needs the withCredentials option to try to pass cookie cross-domain; however, I haven't found a definitive answer whether there's something similar for WS or not. Here the author of a similar question just assumes that there's no such thing, but is it really so?

Double check that the cookies that you're working with are set with SameSite=None and are secure!
I was having the same issue, thinking that the cookies weren't being sent, because the chrome inspector doesn't show them on websocket connection request, but they seem to be once you mark them with same site none and secure.
Alternatively, to quickly check if that's the problem, you can disable the SameSite requirement in chrome://flags/

On another project I've learned a "correct" way to handle this. Usually a higher level protocols are used with WS, like STOMP protocol. It has specific implementation for auth, so no cookies are needed actually; it has no drawbacks regarding CORS.

Related

Proxied Browser Requests with Cookies through a node server

What I am trying to achieve is displaying html content to a user from another server (external server That I do not own) that is normally accessed through a browser.
To get the right html to display to the user, cookies related to that server's domain must be provided.
APPROACH 1:
Easiest approach I tried is using an iframe. And of course, I got the usual CSP error from the chrome console:
Refused to frame '{{URL}}' because an ancestor violates the following Content Security Policy directive: "frame-ancestors 'self' {{ACCEPTED DOMAINS}}".
APPROACH 2:
I made a local proxy server in node.js and tried to setup a proxied request in browser axios:
axios.get("{{URL to external server}}", { proxy: { host: "localhost", port: 5050 }});
I quickly realized that axios proxy is a node only feature per this issue.
CONCLUSION:
I can't find a way to make a GET request to get html in a browser to a cookie protected and CSP protected server/domain. If I am able to display html in the first place, I can probably use the same system to show a login page to update the user's cookies. Just a heads up I am using react / node.js.
If you know of a better approach that completely scraps away my code or uses a different technology, please share!
Thank you in advance.

How can I send cookies of a Web Api back to it from a different front-end application

I have a web application that serves only static contents - HTML, CSS and JavaScript. I have another application which is an ASP.NET Web API. Both applications are on same machine on different ports (for testing purpose and they could be on different machine or domain in production environment). When I browse the web application, it gets both cookie as well as form token of Anti CSRF on first ajax call from Web API. So I am setting the body token as header with setRequestHeader function of XMLHttpRequest. It doesn't seem there is any need to set the cookie token since cookies are restricted with HttpOnly Attribute for a security reason and as far as I know browser is responsible to send the cookie to whichever domain the cookie belongs to.
However, when I make consecutive ajax calls, instead of both these tokens being passed back to server, only the header token is being received by the server.
Currently the Web API is set with CORS restriction for the web application. But if the problem was related to cross origin then I guess, headers could not have been passed as well, correct me if I am mistaken.
So can anyone help me with this problem? I just want to be able to send cookies from one application to another without compromising in terms of security.
Take a look Cookies With My CORS and Set-Cookie in HTTP header is ignored with AngularJS

securing CORS: is there a security scheme with cookies?

I have two web-servers responding on two different ports. I have the main web server that serves a website with a lot of javascript behind HTTP digest authentication, the secondary webserver only executes CGIs that can be directly accessed, always by using HTTP digest, or that can accessed with CORS by the ajax requests related to the main webserver. Both servers share the same users credentials.
My problem is that I don't want the browser to prompt for credentials when the javascript is making requests to the secondary webserver.
I came out with the idea that I could add some special header in the ajax request to the secondary web-server, and if this header is present I can ignore the HTTP authentication. Since the servers share the users credentials, if the user is able to log in into the main web-server, he'll be able to login into the second one as well.
Using a fixed header is of course useless. So the question is: is there a mechanism in CORS to tell the secondary webserver that the user is already authenticated in the first one? Something like a safe way to exchange tokens in cookies?
If it is only the ports that are different cookies will be shared across these origins. So if you know for sure that a cookie is set once the user accesses origin 1, they will be included in requests to origin 2, as long as (assuming you're using XMLHttpRequest) withCredentials is set to true.
Now of course those cookies should contain some authentication data that you verify before you let them bypass HTTP authentication.
And hopefully you're using HTTPS so that the credentials are safe from network attackers.
I'm not sure this has anything to do with CORS. What you need is a single-sign-on solution for the two different servers. You could implement a full-blown OAuth solution, or write a simple one yourself.
For a simple token-based authentication, you'd do the following:
When the user logs into your website, send down a expiring token (over SSL) that grants the user access to the web service.
Take the token and do a GET request to a non-authenticated endpoint in the web service. If the token is valid and non-expired, send an authentication token back to the browser.
As long as your web service implements HTTP authentication properly, the cookie will be set and the service calls won't prompt for credentials.

What is the correct CORS entry for limiting an http:// connection to a remote, hosted web server from a grunt web server on a home network?

I've setup a remote, hosted javascript server (DreamFactory Server http://www.dreamfactory.com/) that responds via REST API's.
Locally, I'm running an Angularjs application through the grunt web server via $grunt serve
https://www.npmjs.com/package/grunt-serve
I have setup CORS on the remote server to allow '*' for multiple http:// connection types. THIS WORKS CORRECTLY.
My question is how I can limit the CORS configuration to only allow a connection from my home, grunt web server?
I've tried to create an entry for "localhost", "127.0.0.1", also my home Internet IP that is reported from whatismyip.com, the dns entry that my provider lists for my home IP when I ping it, a dyndns entry that I create for my home internet IP... None of them work, except for '*' (which allows any site to connect).
I think it is an educational issue for me to understand what that CORS entry should look like to allow ONLY a connection from my home web server.
Is this possible? If so, what and where should I be checking in order to find the correct entry to clear in the CORS configuration?
-Brian
To work and actually apply restrictions, the client requesting the connection must support and enforce CORS. In an odd sort of way (from a security point of view), restricting access using CORS requires a self-policing client (one that follows the prescribed access rules). This works for modern browsers as they all follow the rules so it generally works for applications that are served through a browser.
But, CORS access restrictions do not prevent other types of clients (such as any random script in any language) from accessing your API.
In other words, CORS is really about access rules from web pages that are enforced by the local browser. It doesn't sound like your grunt/angular code would necessarily be something that implements and enforces CORS.
If you really want to prevent other systems from accessing your DreamFactory Server, then you will need to implement some server-side access restrictions in the API server itself.
If you just have one client accessing it and that client is using "protected" code that is not public, then you could just implement a password or some sort of logon credentials and your one client would be the only client that would have the logon credentials.
If the access is always from one particular fixed IP address, you could refuse connections on your server from any IP address that was not in a config file you maintained.
You can't secure an API with CORS, for that you will need to implement an authentication scheme on your server. There's essentially 4 steps to do this.
Update the headers your server sends with a few additional Access-control statements.
Tell Angular to allow cross-domain requests.
Pass credentials in your API calls from Angular.
Implement an HTTP Authentication scheme on your web server or in your API code.
This post by Georgi Naumov is a good place to look for details of an implementation in Angular and PHP.
AngularJS $http, CORS and http authentication

source map HTTP request does not send cookie header

Regarding source maps, I came across a strange behavior in chromium (build 181620).
In my app I'm using minified jquery and after logging-in, I started seeing HTTP requests for "jquery.min.map" in server log file. Those requests were lacking cookie headers (all other requests were fine).
Those requests are not even exposed in net tab in Developer tools (which doesn't bug me that much).
The point is, js files in this app are only supposed to be available to logged-in clients, so in this setup, the source maps either won't work or I'd have to change the location of source map to a public directory.
My question is: is this a desired behavior (meaning - source map requests should not send cookies) or is it a bug in Chromium?
The String InspectorFrontendHost::loadResourceSynchronously(const String& url) implementation in InspectorFrontendHost.cpp, which is called for loading sourcemap resources, uses the DoNotAllowStoredCredentials flag, which I believe results in the behavior you are observing.
This method is potentially dangerous, so this flag is there for us (you) to be on the safe side and avoid leaking sensitive data.
As a side note, giving jquery.min.js out only to logged-in users (that is, not from a cookieless domain) is not a very good idea to deploy in the production environment. I;m not sure about your idea behind this, but if you definitely need to avoid giving the file to clients not visiting your site, you may resort to checking the Referer HTTP request header.
I encountered this problem and became curious as to why certain authentication cookies were not sent in requests for .js.map files to our application.
In my testing using Chrome 71.0.3578.98, if the SameSite cookie atttribute is set to either strict or lax for a cookie, Chrome will not send that cookie when requesting the .js.map file. When there is no sameSite restriction, the cookie will be sent.
I'm not aware of any specification of the intended behavior.

Categories

Resources