Prevent external users to connect websocket (wss)

Viewed 53

I'm building a react-nodejs website at https://example.com and it utilizes websocket (using socket.io library), but right now people can just npm install socket.io-client and connect to my websocket using this:

const {io} = require("socket.io-client");
const socket = io("wss://example.com");

Now they can emit/listen to my backend. At the moment, I use ReCAPTCHA to prevent bots so you need to pass a token to connect to the socket.io server, I was wondering whether there is a better solution than this.

1 Answers

You are correct, you can't prevent people from trying to connect to your socket.io server manually with a custom script using socket.io-client. Normally that's a reason for you to design the server in a way, that connected client sockets can't do any harm. Client sockets are usually on the receiving side.

But of course there is a best-practice on how to authenticate the connecting clients, and, if the authentication is failing, to prevent the connection. Checkout out the socket.io Documentation about client options. There is an auth field available :

Client

import { io } from "socket.io-client";

const socket = io({
  auth: {
    token: "abcd"
  }
});

Server

io.on("connection", (socket) => {
  console.log(socket.handshake.auth); // prints { token: "abcd" }
});

So once the user is logged in, use the JWT (Token) (assuming you having a JWT Authentication in place) and pass it during establishing the connection. Then validate the JWT on the server side.

client-certificate authentication

There is also a more advanced option for client authentication which uses certificates:

Client

const fs = require("fs");
const socket = require("socket.io-client")("https://example.com", {
  ca: fs.readFileSync("./server-cert.pem"),
  cert: fs.readFileSync("./client-cert.pem"),
  key: fs.readFileSync("./client-key.pem"),
});

Server

const fs = require("fs");
const server = require("https").createServer({
  cert: fs.readFileSync("./server-cert.pem"),
  key: fs.readFileSync("./server-key.pem"),
  requestCert: true,
  ca: [
    fs.readFileSync('client-cert.pem')
  ]
});
const io = require("socket.io")(server);
Related