Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js & Socket.io: Self-signed certificates for a secure websocket connection

I've been running across the internet looking for a straight forward answer, but most solutions involve using Express and serving HTTP content for secure connections. I'm more interested in a secure web socket connection (wss) for Node.js and socket.io

I don't use Node.js for HTTP requests. I use the socket.io module that works with Node.js to deliver messages in real time to my applications. I only use node for the web socket connection.

I'll explain breifly what my setup is. I use Django as my HTTP backend. Users make a request to Django, Django forwards the contents of that request to Redis, Node.js listens in on one of Redis' channels, it processes the contents and sends the message to the appropriate recipient.

Pretty simple and straight forward. Everything works fine. But I'm afraid that the websocket connection to Node.js is unsecure. When Node.js sends a message to the recipient, I don't want anyone snooping in between and intercepting the message. I would like to make sure my users feel safe and trust the service I have built for them.

I looked into self-signed certificates and certificates from a CA. Both provide the same level of security. Since I am only using Node.js for socket.io and not serving HTTP content, a self-signed certificate will work absolutely fine (the service I have built is for mobile, not for browsers!)

Below is my implentation of socket.io:

var io = require('socket.io').listen(8000);
var redis = require('socket.io/node_modules/redis')
var redisChannelConnection = redis.createClient(6000, "12.345.678.9");
var redisServer = redis.createClient(6000, "23.456.789.1");

// Subscribe to Redis Channel
redisChannelConnection.subscribe('messages');

io.sockets.on('connection', function (socket) {
     socket.emit('message', 'Hello World');
     }

I have just written up a simple connection function so far. It works as a normal websocket connection. But I would like to make it a secure websocket connection. How many I go about doing this?

Thank you for your help.

like image 585
deadlock Avatar asked Mar 23 '14 16:03

deadlock


2 Answers

First you need to create an HTTPS server in node (for which you need a certificate):

http://nodejs.org/api/https.html
How to create an HTTPS server in Node.js?

Then you should use that server to initiate Socket.io.

var io = require('socket.io').listen(myHTTPSserver);

That should basically be all there is to it.

There is two ways to secure your connection from man-in-the-middle attacks:

  • Using a signed certificate, and having the client check that signature. The internet is stuffed with explanations for why this actually a pretty poor solution.
  • Making sure that the client refuses to connect with anything but your certificate. Any decent SSL/TLS library will allow you to specify a certificate that must be used for an outgoing connection, if the key on the server end doesn't match that certificate the connection is aborted. This does everything that the signature system should do, but doesn't rely on every single CA cert in the world being honest, or any of the other shortcomings of the CA system.

Your Django/Node.js combination sounds quite odd, is it correctly understood that clients make requests on one channel and receive the response on another channel?

While it could technically be okay, it sounds like a recipe for making odd vulnerabilities. If you must use both, consider making Node a proxy for the Django content and have Node handle all authentication.

In any case, I seriously doubt that encrypting just one of two channels is enough, once a hacker has pwned one channel there will most likely be a plethora of escalation options.

like image 72
aaaaaaaaaaaa Avatar answered Oct 26 '22 23:10

aaaaaaaaaaaa


I looked into self-signed certificates and certificates from a CA. Both provide the same level of security.

No, they don't. The security of SSL has nothing to do if you do HTTPS (e.g. HTTP inside SSL) or wss (e.g. kind of socket inside HTTP tunnel inside SSL). SSL provides end-to-end encryption, but this end-to-end can only be guaranteed if you can identify the other end. That's what certificates are for. A certificate signed by a trusted CA means, that some CA looked at the certificate data and kind of made sure that the data in the certificate matches the owner. But a self-signed certificate just says, that the owner itself thinks that everything is fine, but nobody trusted had a look at it. This is the reason self-signed certificates are not trusted by default and each user has to explicitly trust the certificate (hopefully after he has validated the owner somehow).

like image 20
Steffen Ullrich Avatar answered Oct 26 '22 23:10

Steffen Ullrich