Creating a Secure (TLS) Node.js MVC Application

Recently, I investigated node.js and came up with a pretty solid pattern or starting project for an MVC style application. There was one problem – it used an insecure transport (normal plaintext HTTP). The world is moving towards universal encryption and I contend that this should be the default case even when developing. You can use a variety of packet sniffing technologies when you are developing in plain text that are simply not available or severely restricted when you transition to a secure communications channel. So develop with a secure server.

That doesn’t mean you have to go spend money on secure signed certificates. You can use “self-signed” certificates to do the work. There are plenty of articles on how to produce self-signed certificates for Ubuntu, CentOS and Mac. This article shows you how to produce self-signed certificates suitable for a node application with Windows.

Creating an SSL Certificate

Most instructions for creating and using an SSL certificate in node require you to produce two .pem files – one key and one certificate. This is great if you have access to OpenSSL. That tool makes it really easy to produce the appropriate files. It’s not so easy on Windows. However, it is easy to produce a .pfx file – a secure bundle of all the bits you need.

First off, start up the IIS Manager and open Server Certificates:


Click on Create Self-Signed Certificate:


Enter a friendly name, for example “Development Node Certificate” and click on OK:


Now you can click on the certificate you just created and then click on Export:


Save the .pfx file somewhere. Make sure you specify a strong password and note it down – it goes in your configuration.


Writing a Node/Express HTTPS Server

The second part to this process is to create a Node/Express HTTPS Server. I started in Visual Studio by using the Basic Node.js Express 4 Application. First off, create a file config.json in the root of the project. Mine looks like this:

  "port": 3000,
  "host": "localhost",
  "https": {
    "pfx": "C:/Users/photo/Certificates/node-dev.pfx",
    "passphrase": "my really secure password that no-one will guess",
    "ciphers": "ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL",
    "honorCipherOrder": true

In secure servers, you need to specify both the host and the port. The interesting stuff is in the https block. The pfx field is the path to my PFX file and the passphrase is the secure password that I created when exporting the certificate.

The next two lines are important for anyone who is running a production secure server. The first line tells the server what ciphers to accept. I don’t accept insecure ciphers and this line gets updated when new threats invalidate a cipher. The second honorCipherOrder tells the server to insist on more secure ciphers over less secure ciphers. This is a key component to protecting against SSL BEAST attacks.

Next, edit ./bin/www – this is the bootstrap code for starting the server. Replace the contents with the following:

#!/usr/bin/env node

var fs = require('fs'),
	https = require('https'),
	app = require('../app'),
	config = require('../config.json');

app.set('port', process.env.PORT || config.port || 3000);

console.log("Loading PFX File");
var pfxFile = config.https.pfx;
config.https.pfx = fs.readFileSync(pfxFile);

console.log("Starting Server");
var server = https.createServer(config.https, app).listen(app.get('port'),;

The standard version uses the built-in code in Express to do the listening. This version creates a HTTPS server context explicitly. Also, I turn the pfx path into a buffer containing the PFX data prior to calling the createServer. Given that I’ve abstracted all the configuration to config.json, this can be considered boilerplate.

Finally, generally I want the browser to start up when I run the project. That doesn’t happen automatically. Right-click on the project and select Properties. Then set the Launch URL to https://localhost:1337/ replacing the port with whatever port is in the Node.js port box:


You should be able to run this and check how the connection is configured. In Chrome, right-click on the page and select Page Info. In Internet Explorer, right click and select Properties:


Note the TLS v1.2 – you want to see at least that. If you see SSLv2, SSLv3 or any TLS prior to v1.2, then your page is not as secure as you think.

One final note – and it should be obvious. NEVER check in your pfx file. If your config file contains your password, then don’t check that in either.

To get around the password problem, I tend to use a process.env.SSLPASSPHRASE over-ride. For example:

var passphrase = process.env.SSLPASSPHRASE || config.https.passphrase || "";
config.https.passphrase = passphrase;

Hopefully, this assists those node developers who happen to like Windows too!