You're reading from Socket.IO Cookbook
Although the WebSocket protocol provides several opportunities for more direct communication between the client and the server, people often wonder if Socket.IO is actually as secure as something similar to the HTTP protocol. The answer to this question is that it depends entirely on how you implement it. WebSockets can be easily controlled to prevent malicious or accidental security holes, but with any API interface, your security is only as tight as your weakest link.
In this chapter, we will explore several topics related to security in Socket.IO applications. From authentication and validation to how to use the wss://
protocol for secure WebSockets, these topics will cover the entire gamut.
Most applications need a way to authenticate users. In this recipe, we will create a simple form to create and authenticate users. We will keep our authenticated users in the session so that we can maintain our authenticated state even when the page is refreshed. In order to get our users, we will pass a random token to the socket, once it authenticates, that it can use to retrieve the authenticated profile.
For this recipe, we will use MongoDB to persist our users. We will also use the the md5 npm
module to hash our passwords before we save them to the database.
To implement basic authentication, follow these steps:
First, we will need to create our server. The server will require several additional modules that we will build next. Use the following code:
var express = require('express'), app = express(), http = require('http'), socketIO = require('socket.io'), server, io; app.get('/', function (req, res) { res...
Now that we are able to perform basic authentication with Socket.IO, let's take a look at a token-based approach that handles authentication more securely, such as JSON Web Tokens, or JWT.
JSON Web Tokens are an URL-safe means of representing claims to be transferred between two parties. The claims in a JSON Web Token are encoded as a JSON object that is digitally signed using JSON Web Signature. With this approach, we can securely send a salted web token to the client to use on subsequent requests.
For this recipe, we will use the jsonwebtokennpm
package to create secure JSON Web Tokens. The package can be installed by running npm install jsonwebtoken –save
in your terminal.
When we write data to a database, it is important to perform validation on the server side to ensure that the data is in the type and format that we expect it to be in. In this recipe, we will demonstrate how we can emit data to the server and emit messages back if there is a success or an error.
We will use promises to handle success and error states. Depending on your version of Node, you may need to install the promise module with npm install promise –save
. Promises are a feature of ES6, so they will eventually be native in Node.
To handle validation on the server side, follow these steps:
First, we will create a method for performing some validation on the server side. Typically, your validation would take place in your ORM, but we will perform it in plain JavaScript here to exhibit the concept. We will resolve a promise if the data is valid and reject the promise if it is invalid. Use the following code:
function validatePerson ...
Socket.IO is really good at getting around cross-domain issues when you create a request from a client in a different domain than the domain your server lives on. You can easily include the Socket.IO script from a different domain on your page. It will work just as you may expect it to.
There are some instances where you may not want your Socket.IO events to be available to every other domain. Not to worry! We can easily whitelist only the http referrers that we want so that some domains will be allowed to connect and other domains won't.
To lock down the HTTP referrer and only allow events to whitelisted domains, follow these steps:
Create two different servers that can connect to your Socket.IO instance. We will let one server listen on port
5000
, and let the second server listen on port5001
:var express = require('express'), app = express(), http = require('http'), socketIO = require('socket.io'), server, server2, io...
WebSocket communications can either take place over the ws://
protocol or the wss://
protocol. They can be thought of in similar terms to the HTTP and HTTPS protocols in that one is secure and one isn't. Secure WebSockets are encrypted by the transport layer, so they are safer to use when handling sensitive data. The main feature of HTTPS (and wss) is that socket is encrypted from client to server, so if we're in the same network and we try to sniff the content, we won't see anything legible.
If your application uses the HTTPS
protocol, you will also need to use the wss
protocol for your WebSockets. Many browsers do not allow un-secure content when they use HTTPS.
In this recipe, we will learn how to force our Socket.IO communications to happen over the wss://
protocol for an extra layer of encryption.