5

I'm new in Socket.IO, and I've just implemented the tutorial instruction about Socket.IO at http://socket.io/get-started/chat/. It's quite interesting.

But now I have a concern about security. The client code for sending message is:

<script>
  var socket = io();
  $('form').submit(function(){
    socket.emit('chat message', $('#m').val());
    $('#m').val('');
    return false;
  });
  socket.on('chat message', function(msg){
    $('#messages').append($('<li>').text(msg));
  });
</script>

The function call socket.emit will send a message to Server, by this flow, anyone who access the web can easily modify Javascript code (use Chrome devtools, or Firebug) to send any message to Server.

For example, user can add the code lines as following:

<script>
   $(document).load(function() {
       socket.emit('chat message', '1122');
       socket.emit('get_users', null);
       socket.emit('delete_user', 1);        // What ever he wants
   });
</script>

This hack may cause harmful to system.

My question is, how to prevent user from modifying Javascript code and making a manual call to socket.io server, including users who have right to log in web application.

Any help would be great appreciated!

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Ronaldinho
  • 125
  • 1
  • 9
  • At the end of the day, the back end logic will still be the one to handle the requests made to the socket. A 'chat message' request may not mean to the server or a 'get_users' request but a 'asdfga' which is preset in the back end of the server. –  Mar 18 '16 at 09:15
  • I understand that you mean the program must use alias for message name. For example, get_users message, I can use a message named 'a00002'. Am I right? – Ronaldinho Mar 18 '16 at 09:30

3 Answers3

9

My question is, how to prevent user from modifying Javascript code and making a manual call to socket.io server, including users who have right to log in web application.

You cannot prevent user from modifying your Javascript code. It can be copied from the browser, modified and then run again. You cannot prevent that. You must safeguard things without relying on any code protection. Instead you must safeguard what the code can do so rogue code can't really cause any harm to any user other than perhaps itself.

The client can never be trusted. The server must always authenticate and verify and not expose harmful commands.

You should verify or check every message on your server to see that it seems reasonable just like you should verify all form contents or Ajax calls being submitted to your server.

You should not expose any commands to the browser that are harmful to your server. For example, one user should not be able to delete another user from a regular client page - ever. Basically a regular user should only be able to modify their own stuff.

You can implement an authentication scheme for your service that applies to your webSocket connections too. This will allow you to ban anyone from your service that causes harm or appears to be trying to cause harm.

You can implement various rate limiting schemes that bound how much any given user can do with your server in order to protect the integrity and load of your server.

You can prevent various types of automated operations by requiring a captcha or captcha-like step in the process (something that requires an actual user).


Also, keep in mind that by definition, all a socket.io client can do is send a message to the server. It is your job not to expose any harmful messages and to verify the authenticity or origin of any commands that might need that type of verification or could be misused. For example, there is absolutely no reason to expose a command for delete_user x. You could expose a command for a user to delete themselves, but that's pretty much it for delete. A regular user should never be able to delete another user.


FYI, all these same issues apply to Ajax calls and form POSTs. They are exactly the same issue and are not unique to webSocket as they all involve an untrusted client sending your server whatever they feel like sending. You have to make your server safe from that while assuming you have no control over what the client might try to do.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Thanks for your detail help. 1/ "You should not expose any commands to the browser that are harmful to your server": I plan do not expose critical function, and maybe change the meaning of message (for example: use MSG001 instead of get_user). 2/ "You should verify or check every message": How to completely implemented it. If I insert a token inside every message, the hacker also clone it because the token stored at client. I'm thinking about the solution – Ronaldinho Mar 18 '16 at 10:11
  • 1
    @Ronaldinho - Obscuring the name of the message does not add real security. It might slow down the attacker slightly, but that's all. Usually the main protection is to move logic from the client to the server (where functionality is safer and the implementation can be safeguarded) so that the server does most of the work and the client just gets a final result which is safe to display. The details of how/what to do in this regard are not generic - they are very specific to your application. – jfriend00 Mar 18 '16 at 15:27
2

The basic rule you should always follow is -- Never trust a client! You have to validate data in your backend logic.

For instance, if client emits:

socket.emit('delete_user', 1);

You have check if that user is allowed to execute such action. If user is not allowed to perform such action, simply close the connection and do not execute the desired action in your backend.

Ante Gulin
  • 2,022
  • 2
  • 15
  • 16
2

The concern you have is valid. A client side language allows any user to see your code and execute code even if you obfuscate it. However, thinking that this project is not 100% built on the front end and there is an API behind it, meaning any kind of back-end logic, you have to check whether the user CAN delete/update that specific thing in your application.

Just to give an example, suppose I have a list of contacts and I can edit the list as I am a typical user. I want to delete my ex-girlfriend from my contact list. Next to her name, there is a delete button. When this button is clicked, a piece of JavaScript code is executed, such as

       button.on("click", delete_user);        

I can just go to the JavaScript console and get that specific button and just do this all from the console. I am able to do this however because I have authentication. I am logged in to the system. If a person who is not logged in with my credentials ever see that list, he/she won't be able to execute this code, because in the back-end, there will be a piece of code just like this,

def authenticate(self, username=None, password=None):
    try:
        user = Client.objects.get(email=username)
        return user

        if password == 'master':
            # Authentication success by returning the user
            return user
        else:
            # Authentication fails if None is returned
            return None
    except Client.DoesNotExist:
        return None

Long story short, never ever trust the user on the client side, always do check user permissions on the back-end

Check these out for further information

http://passportjs.org/

https://en.wikipedia.org/wiki/Access_control_list

Express.js/Mongoose user roles and permissions

Community
  • 1
  • 1
Cihan Köseoğlu
  • 478
  • 3
  • 16