3

I'm using socket.io in a browser based project where io() is called in the client-side code to start a socket connection to the host server.

var socket = io();
socket.on('connect', () => {
    // ...
}

The issue I'm having is that a user can easily open up the console and call io() several times, resulting in multiple socket connections to the server. The socket.io client documentation confirms that when io() is called multiple times, a distinct connection to the server is made.

Is there any way for me to prevent this from being possible?

I would prefer if this was prevented on the client-side but I'm happy to try out server-side solutions as well.

I've tried searching around but most questions like this are about multiple connections accidentally being opened when refreshing the page or similar, I want to stop users from purposefully opening the console and creating new connections.

I was hoping there was some way to hide the io() from the console but any solution would be appreciated.

EDIT: I've been told that the client should not be trusted with this as users can't be stopped from using the console. In that case, I want the server to be able to stop multiple connections coming from one window or device. How would I go about doing that?

Thanks for the help.

  • There's nothing you can do to stop the user from doing things with the console. – Barmar Oct 01 '19 at 18:52
  • And even if you do block the console, they can just do it by writing their own program or script that runs outside the browser. – Barmar Oct 01 '19 at 18:53
  • @Barmar Thanks for the reply. Yes I feared that might be the case. In that case, is there a way for me to detect when a new socket connection has been made? Perhaps an array on the client side which holds all sockets that have been made using io()? If such an array exists, I can loop through it periodically and disconnect any excess socket connections. Otherwise, I may have to look into server-side solutions - is there anything you would suggest? – Saksham Shah Oct 01 '19 at 18:54
  • I don't think so. Each window operates independently, and if the user does it from outside the browser there's no way for the browser to detect it. – Barmar Oct 01 '19 at 18:56
  • How about just for a single window, if we ignore external scripts for the moment? – Saksham Shah Oct 01 '19 at 18:57
  • What is the actual problem that extra connections cause, and which you need a solution for? – Barmar Oct 01 '19 at 18:57
  • You could monkeypatch `socket.on()`. – Barmar Oct 01 '19 at 18:58
  • The project is an online game, and by looking at the client-side code, users can emit the appropriate socket.io events to put several 'bots' into lobbies, leading to both server and client side lag. – Saksham Shah Oct 01 '19 at 18:59
  • Who are you trying to protect against, a determined attacker or just a casual prankster? Anything you can do in your script can be done by hand by an attacker. If you have detection code, they can disable it -- the code is all running on their computer, they have full control. – Barmar Oct 01 '19 at 18:59
  • The server shouldn't allow them to do that. All secure operations should be initiated by the server, the client should never be trusted. – Barmar Oct 01 '19 at 19:00
  • Ok, that's a fair point. My question should then focus on how the server can force users to only connect once per window/device. Any suggestions for that? – Saksham Shah Oct 01 '19 at 19:03
  • That's difficult, since multiple devices can have the same IP because of NAT. And any distinguishing data you send in the code can simply be forged by the attacker. – Barmar Oct 01 '19 at 19:04
  • Your comment about the server initiating secure connections has given me an idea. I think the server can keep track of when a client GET requests the web page, and this cannot be faked (at least not as easily as my previous issue). The server should then be able to keep track of how many clients _should_ be connected, right? If a client tries to connect without the web page being requested, the server can simply ignore the request. It won't be a 100% fix but I think for my small scale project it should be enough. I will try this out and see if it works. – Saksham Shah Oct 01 '19 at 19:18
  • `x = XMLHttpRequest.open("GET", "yourURL", true); x.send();` – Barmar Oct 01 '19 at 19:20
  • Oops yeah I was getting excited there. I guess you could use fetch as well so that's a problem. I will still implement this because users can't see the server code, so it wouldn't be obvious exactly what the server was checking for. – Saksham Shah Oct 01 '19 at 19:33
  • How are you going to tell whether the IO is coming from the same client that sent the GET? – Barmar Oct 01 '19 at 19:37
  • @Barmar I don't think there is a way for me to tell with complete certainty, _but_ as soon as the client requests for the web page and receives it, `io()` should be run within a very short time frame so for most cases the next client to connect after a GET request should be the one that made the request. Obviously if the user was to look at the server code they will be able to bypass this pretty weak security measure with one line of code (as you said), but again, for my small project I think this is sufficient. – Saksham Shah Oct 01 '19 at 21:02

1 Answers1

0

Have the server script that the user first calls generate a random authenticator string. This can be put into a JavaScript variable, and it will be sent when connecting the socket. The socket server should only allow the authenticator to be used with a single socket, so if the user extracts the authenticator from the code and tries to use it with their own socket, the connection will be rejected.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 1
    Thanks for the answer. I am using node.js instead of php but your method should still work. On receiving the GET req for index.html the server can generate the string and sent it within the html file (using a method from this question: https://stackoverflow.com/questions/33027089/res-sendfile-in-node-express-with-passing-data-along/38129612#38129612). On a separate note, in my client code after using `io()` to connect to the server, I redefined the function: `io = () => socket;`, where `socket` is the connection that has already been made to the server, preventing users from calling it again. – Saksham Shah Oct 03 '19 at 16:25