7

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.

deadlock
  • 7,048
  • 14
  • 67
  • 115

3 Answers3

7

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.

Community
  • 1
  • 1
aaaaaaaaaaaa
  • 3,630
  • 1
  • 24
  • 23
  • 1
    It is possible to combine multiple content servers here (Node.js for io and Django, Rails, ASP...) A bit tricky but by keeping them separated it is possible to deploy socket.io on an already working web application built using other technologies. The main challenges are: (1) Redundancy of socket.io servers (to be able to handle communication failures or live-deployment) (2) Communication between the existing web server and socket.io; pipes, REST interface, protobuf, even communicating via a DB or files is an option here. Choose wisely though as this can be the part that dooms the project – Txangel Apr 01 '14 at 14:46
2

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).

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • 1
    this is my source http://webdesign.about.com/od/ssl/a/signed_v_selfsi.htm also, maybe I wasn't clear, but my application isn't for the web. I'm doing strictly mobile, more specifically my iOS application which I trust and my back-end. – deadlock Mar 23 '14 at 18:07
  • "Both certificates will generate a site that cannot be read by third-parties. The data sent over an https connection or SSL, will be encrypted regardless of whether the certificate is signed or self-signed." -- The encryption is all I care about. The user won't be exposed to whether it's a self-signed certificate or verified by a CA since all requests are coming from my iOS application. – deadlock Mar 23 '14 at 18:11
  • 1
    In my eyes that source is simply wrong. If you do encryption with a key exchange (e.g. SSL) instead of a secret pre-shared key you need to identify the other site, because otherwise you might talk to a man-in-the-middle and not notice. So a certificate is not only about giving the customer some information, it is to make sure you talk to the intended party and get end-to-end encryption and not end-to-mallory-to-end encryption. The only usable way for a self-signed certificate in your application would be to have its fingerprint hardcoded into your app. – Steffen Ullrich Mar 23 '14 at 18:17
  • 1
    It does not matter if it is Web or mobile. Maybe you should have a look at http://www.theregister.co.uk/2014/02/14/fake_ssl_cert_peril/. "40% of iOS-based banking apps tested by IOActive are vulnerable to such attacks because they fail to validate the authenticity of SSL certificates presented by the server." – Steffen Ullrich Mar 23 '14 at 18:17
  • I understand your points, thank you. I learned something new today. – deadlock Mar 27 '14 at 00:29
1

First, I completely agree with the other answer that self-signed certificates are not as secure but more on that in a moment... What you want to do is require "https" instead of "http" and pass in your certificate options into createServer to create your HTTPS app. The options are pretty much the same as the TLS options here. Then when you call listen for socket.io, you'll be listening via HTTPS instead of HTTP.

Now back to the real issue which is a misunderstanding of the purpose of the CA. I agree that even a self-signed certificate will encrypt the content, but a self-signed certificate is not validated by anyone else meaning that anybody else can generate their own self-signed certificate that is just as valid. A malicious user at a coffee shop could set up a WiFi network that seems legitimate. In control of that network he can put himself in the middle of all requests. All he would have to do is generate his own self-signed certificate for your domain name and he would be able to not only decrypt, but also modify in transit all of the requests. This applies not just to browsers, but also mobile apps for Android, iPhone or anything else. The certificate authority is in place for operating system to dictate which root certificates are trusted to issue certificates. Because the malicious user can't register a certificate for your domain name at a trusted certificate authority, any certificate validated in that way guarantees that the computer on the other end is in fact the intended computer. Self-signed certificates are fine in development, but using them in production puts any data sent via your application at risk of spoofing your server, information disclosure, and message tampering.