Websocket API security when accessing from a browser - javascript

Wondering about my security approach.
We have a web server with some kind of backend, and a JS frontend.
Users have to login through the frontend, with regular GET/POST requests, they get a HTTP-only session cookie set as well as a particular "wstoken" string that is available to the JS (by setting it with <script>wstoken = 'xxx';</script>
The frontend then opens a WS connection to the API server and sends an authentication request with the wstoken. If the wstoken matches what we have for the user in the DB, we accept the authentication request and consider that WS connection to be authed to that user.
I'm wondering if I'm doing it right.

Related

Google IAP Authentication for WebSockets

We have a Google http(S) LB in front of a Google Compute VM, and we are routing a subdomain to the backend which exposes only a wss endpoint. I couldn't find any example for javascript code how to use Authentication with Google IAP and OIDC Tokens.
Does Google IAP support query parameters for the authentication ?
I found this entry:
Bearer authentication for websocket
Thanks for any advice
There is no method in the JavaScript WebSockets API to customize WebSocket headers from JavaScript, you’re limited to the “implicit” auth (i.e. Basic or cookies) that are sent from the browser. Further, it’s common to have the server that handles WebSockets be completely separate from the one handling “normal” HTTP requests. This can make shared authorization headers difficult or impossible. One way to attain this is using a “ticket”-based authentication system.
When the client-side code decides to open a WebSocket, it contacts
the HTTP server to obtain an authorization “ticket”.
The server generates the ticket. It typically contains some sort of
user/account ID, the IP of the client requesting the ticket, a
timestamp, and any other sort of internal record keeping you might
need.
The server stores this ticket (i.e. in a database or cache), and
returns it to the client.
The client opens the WebSocket connection, and sends along this
“ticket” as part of an initial handshake.
The server can then compare this ticket, check source IPs, verify
that the ticket hasn’t been re-used and hasn’t expired, and do any
other sort of permission checking. If all goes well, the WebSocket
connection is now verified.
Refer to the link for websocket security and related stack posts HTTP headers in websockets client API and Websocket authentication.

Web socket authentication, is using a query parameter safe enough?

We're developing a web application that will fetch some data over a websocket. We serve it from CloudFront over SSL, the back-end is on AWS. We authenticate the users with Cognito for signing in with the application, and we would like to use the Cognito token to set up authentication for the websocket as well. Also, we want the token to be part of the first connection attempt, so that we don't open a connection to anyone, and then wait for some magic message containing auth, that could probably lead to DDoS attacks.
The first thought was to add the token to an authorization header, but the websocket standard doesn't support adding headers.
Second, we thought about adding an X-Authorization cookie with the token, that way the cookie would be sent as part of the request to open a socket. This failed (probably) because in development, the cookie domain is set to "localhost", and will not be sent to the websocket url of aa.bb.com.
Our next move is to append the token to the URL as a query parameter, and it seems to be working.
Now, my question is, is this safe enough, or should we consider something like a two-step approach, first get a sign-in token from another endpoint, then use that one as a query parameter when opening the websocket ?
As long as your traffic is over SSL whatever solution works has the same security as the SSL no matter what method is used i.e. GET, POST...

How to send custom headers from JavaScript WebSocket client to the server?

I know there are no standard JS WebSocket APIs for the same. My main aim is to send the info like resourceId, routingInfo, auth-token, protocol etc. from JS web-socketclient to the server.
I could think of below few approaches. Kindly share the thoughts if my approach is fine or is there any other better approach:
Can we use cookies for sending the custom headers from client and retrieve them in server side?
Can we use web-storage API for storing them in the browser and retrieve them on server side?
PS: I am using a Java based server
Assuming you're talking about a webSocket connection from a browser, here are your traditional choices for sending additional "header-like" information.
You can encode them as a query parameters on the initial URL which might be fine for everything except auth-token.
If the origin you are connecting the webSocket connection is the same as the origin of your web page, then you can put the parameters into cookies and those cookies will be sent with the original webSocket connection request where the server can retrieve them upon the connection request.
You can make a "conditional" webSocket connection to the server and then send credentials in subsequent webSocket messages. You'd have to implement safety for that on your server so that the "conditionally" connected webSocket was not allowed to do anything else except authenticate itself and probably timeout the connection if appropriate credentials do not arrive shortly.
As it sounds like you may already know, the browser interface to webSockets does not allow custom headers on the initial HTTP request that starts the webSocket connection. Those custom headers are possible from some other kind of client - it's just that the browser interface to a webSocket connection does not have that feature.
Can we use web-storage API for storing them in the browser and retrieve them?
The Javascript in your web page can use the web-storage API to store data in the browser and that data can be retrieved later from another script in a page from the same origin. That data is not available to the server, it is only available within the client.

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.

Node.js cors req.headers.cookie?

I have a node.js server that handles some stuff, it sits on port :9000, I built an authentication middleware to restrict some routes.
I am not able to get the cookie though, so I suspect it is because the req is coming from another place :3000 for example.
I am not trying to get the cookie express sets, I am trying to get a client side PHP cookie from the req
// using var req = http.IncomingMessage.prototype;
req.authenticated = function(callback) {
console.log(this.headers.cookie)
}
So the question is how can I setup so that whenever :3000 makes a request to my node.js server :9000 the cookie is sent with the headers?
You have a number of options:
You can put both servers behind a reverse proxy (such as nginx) and map different URLs from the same authority to different backends.
You could configure Apache (or whatever server your main site is hosted on) to forward some URLs to your Node server using mod_proxy (instructions)
You could host your Node server on a subdomain of the main server, and use the same port, then use domain-wildcard cookies
You could send the auth token explicitly as an HTTP header set by your client code (you'll need to send the raw auth token to the client accessible via JS; beware of XSS attacks)
You could have the main site send a signed request to a URL on the Node.js server to set an auth cookie on its authority (you'll need to do the same on logout, and to prevent CSRF, session fixing, and other attacks; learn about SSO techniques)

Categories

Resources