WebSockets authentication
If you're already doing authentication for the non-websocket part of your app, just pass the session cookie along as the first message after connecting and check the cookie as you normally would.
WARNING: It's been pointed out that the following doesn't work when flashsockets are used:
If you're using socket.io, it's even easier—the cookies are passed through automatically on connection, and can be accessed like the following:
var io = require('socket.io');
var socket = io.listen(app);
socket.on('connection', function(client){
cookies = client.headers['cookie'];
});
SSL/TLS can be used to authenticate both client and server using X.509 certificates. It depends on the web application platform you are using. In apache the SSL_CLIENT_CERT environment variable can be checked for validity against a list of known certificates to be valid. This would not require the use of a full PKI, and would not require you to purchase certificates for each client. Although I recommend using a CA to back your server's ssl certificate.
There are two ways.
One way is to allow anyone to open a websocket connection. Have the client send an authorization token as the first message after the connection is opened. If the client doesn't send a valid token within some time, close the connection.
Another way is to use cookies (they're sent automatically by the browser on each request). This requires that you implement CSRF protection (even more than normal, since there is no same origin policy (SOP) for websockets. You can find details here. The outline is as follows:
- make a "websocket preauth" request to the backend from js using the site's normal auth
- backend returns a CSRF token in the response body and sets a "websocket auth" cookie with
SameSite=Strict
in the response headers - attempt to establish a websocket connection with the backend, with the addition of the CSRF token in a query parameter
- the backend checks
- that the websocket auth cookie and CSRF token are valid
- that the value of the
Origin
header matches an approved domain
- the backend sends a response and upgrades the connection to use websockets
The first method is simpler, but has the disadvantage that it requires you to have some server-side state waiting for the client to authenticate. This can allow an attacker to perform a denial of service attack by consuming all the available sockets.