7

I am new to Node.js and Socket.IO. According to documentation the client side code is something like:

<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io('http://localhost:3000');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script>

It's simple and easy but although it's perfectly fine for local testing I am not sure whether is really secure on a live page since it's exposing the event information of the server.

How do I hide the sensitive information on a page like this ?

Cemre
  • 315
  • 1
  • 5
  • 9

3 Answers3

5

Socket.io creates a WebSocket, and WebSockets follow the normal Same-Origin Policy rules. However, it is possible to make a WebSocket into a cross-origin resource using the Access-control-allow-origin HTTP header, which commonly known as CORS. If for some reason CORS was being used to create a cross-origin WebSocket, then it is possible that this WebSocket could be hijacked by an untrusted domain.

Additionally, a WebSocket is like any other API in that it exposes application logic to attackers. Make sure you address common web application vulnerabilities like the ones found on the OWASP Top 10. Of particular concern is Insecure Direct Object Reference, Injection Attacks, and Broken Authentication and Session Management.

rook
  • 46,916
  • 10
  • 92
  • 181
  • This is ONLY when the connection is made via a browser. Connections can be made from any other agent on the internet (such as any old python script) that does not follow the same-origin policy since that's a client-enforced policy, not a server-enforced policy. – jfriend00 Oct 18 '14 at 21:43
  • @jfriend00 updated. – rook Oct 18 '14 at 21:45
  • Websockets actually are not bound by the same origin policy; however, when a web browser initiates a websockets handshake, it sends along an origin header. The decision whether to allow a connection from a given origin is solely a server-side issue, and can potentially be improperly implemented. If it is not adequately implemented, *that* is when csrf-like attacks with websockets become possible in the browser. – Marcus Oct 19 '14 at 00:33
  • @mtdevens I think that this: https://www.websocket.org/aboutwebsocket.html disagrees... I am pretty sure you need CORS to have a cross-origin WebSocket. Do you have any references? – rook Oct 19 '14 at 02:11
  • It doesn't entirely disagree since the same CORS headers can be used, but as far as my research has shown, they don't have to be set (try it yourself) and obviously not setting them/checking the origin server-side leaves the service vulnerable. See section 1.6 of the RFC and http://www.christian-schneider.net/CrossSiteWebSocketHijacking.html – Marcus Oct 19 '14 at 07:59
3

There are two generic solutions to this problem. Both solutions are based on the approach to not publish information in the public that should not be public. This implies that you have to implement some sort of authentication mechanism in your application, e.g. a log in form that creates a new session (and new temporal session keys). Needless to say, you should also use https / wss instead of http / ws.

The first method is to only publish public events, and fetch the private event data over a separate channel (e.g. a new HTTP request). This is what the Stack Exchange does with live inbox notifications: Sockets are only used to notify subscribers of new inbox messages, while the actual content is only fetched over http(s) when the user clicks on the notification bubble.

The second method is to authenticate the Socket.IO connection before storing the socket server-side. In Socket.IO, you can pass extra information with the handshake via the query option. At the server, read this value and only allow users to create the socket upon successful authentication (example accepted answer is for socket.io 0.9, look here for socket.io 1.x). This key should be treated like a session cookie. When the user signs out, the socket associated with this key should be destroyed and the token invalidated. Ideally, this key should be used only once (i.e. invalidated after first use), but that doesn't well in practice if the connection is unreliable and you have to keep reconnecting to Socket.IO.

As an alternative to rejecting the socket (method 2), you could also accept the socket and use the authentication details to control whether a user is allowed to subscribe to an event or join a room. The client will only receive an event if you send it at the server, so if you don't send the event (e.g. because the user is not in the room where the event is broadcast), then there is no leakage of information.

Rob W
  • 2,113
  • 18
  • 20
0

As with all security questions, you have to describe what your security objectives are. Safe from who? Safe from what kinds of access? How safe from undesired access does it need to be? What levels of authentication and encryption are you willing to add to prevent unwanted viewers of the information?

The scheme you've set up above allows the following:

  1. Any agent can connect to your server with a websocket and subscribe to the 'news' events. So, whatever information is broadcast using the news message is available to anyone.

  2. Actually, any agent can connect to your server with a websocket and read all messages that it broadcasts to all connected sockets. This is not just limited to the news event. If your server sends the data to any random connected websocket, then any random agent can connect via websockets and read that information.

  3. As for the data sent the other way (from your client to the server), that information is only available to someone snooping on the connection (at your ISP, in transport over the internet to the data center where your server is, inside the data center before it gets to your server or anyone with physical access to your server. This data is not readily available to outside agents without access to the transport the packets are flowing on.


The short answer to how you would make the data more secure is pretty much the same as most security questions.

  1. Secure the access, requiring some sort of strong login before access is granted.

  2. Secure the transport with encryption (such as SSL backed by appropriate certificates).

  3. Only send information that requires security on channels that have already put in place the appropriate security.


On the internet, there is no such thing as a server-based API or websocket access that can ONLY be accessed by your own web pages. Access from your web pages is just access from some random endpoint out on the internet and there is generally no difference in access between an intended browser page, a hacker with their own connectivity tools or some rogue server out on the internet trying to access your site. You generally can't tell the difference. There are some tricks to play to make third party access more trouble (such as including ever-changing credentials in each web page that must be used), but without the above three security tenants, it isn't really secure.

jfriend00
  • 524
  • 2
  • 7
  • This post is confusing because the Same Origin Policy (SOP) is never mentioned. The last paragraph is a violation of the SOP. – rook Oct 18 '14 at 21:40
  • @Rook - The same origin policy ONLY applies to access from browsers. It does not apply to any other agent on the internet (e.g. any random Python script) and thus doesn't really matter here because the front door through a browser may have a few obstacles on it, but the side doors are wide, wide open - thus it's not secure until all doors are secured. – jfriend00 Oct 18 '14 at 21:41