Scott Smith

Blog Tutorials Projects Speaking RSS

4 Simple Steps to Secure Your Express Node Application

While not an exhaustive article on securing web applications, the four steps shown here will get you pretty far along in building a secure web application.

HTTPS

One of the first steps you should take to secure your web application is to use HTTPS. For those of you that think it is too hard, too expensive, or too compute intensive, hopefully I can convince you otherwise.

So why would we want to use HTTPS? The number one reason is to keep people and devices from viewing or modifying content being sent and received. There are so many hacks and exploits that can be done when not using a secure connection. It is foolhardy to not use HTTPS.

So how would you get up and running with HTTPS without shelling out a lot of money? Let me introduce you to StartSSL. StartSSL offers free Class 1 certificates you can use to implement HTTPS on your site. While their UI is a bit clunky and cumbersome to work with, the fact that you can get a valid certificate is well worth it.

Cookies

Now that you have HTTPS setup and communication to your server is secure, we need to look at securing your cookies. Assuming your web application has some form of authentication, it is likely you are using cookies to maintain session state.

HttpOnly

HttpOnly is a flag that can be included in a Set-Cookie response header. The presence of this flag will tell browsers to not allow client side script access to the cookie (if the browser supports it). This is important because it helps protect your cookie data from malicious scripts and helps mitigate the most common XSS attacks.

Here is how you can tell Express to set your cookie using the HttpOnly flag:

1
res.cookie('sessionid', '1', { httpOnly: true });

Secure

Equally important as the HttpOnly flag is the Secure flag. This too is included in a Set-Cookie response header. The presence of the secure flag tells web browsers to only send this cookie in requests going to HTTPS endpoints. This is very important, as the cookie information will not be sent on an unencrypted channel. This helps mitigate some exploits where your browser is redirected to the HTTP endpoint for a site rather than the HTTPS endpoint and thus potentially exposing your cookies to someone in the middle of the traffic.

Here is how you can tell Express to set your cookie using the Secure flag:

1
res.cookie('sessionid', '1', { secure: true });

Cross-site Request Forgery

“Cross-Site Request Forgery (CSRF) is an attack that tricks the victim into loading a page that contains a malicious request. It is malicious in the sense that it inherits the identity and privileges of the victim to perform an undesired function on the victim’s behalf, like change the victim’s e-mail address, home address, or password, or purchase something. CSRF attacks generally target functions that cause a state change on the server but can also be used to access sensitive data.” - Open Web Application Security Project)

To mitigate these types of attacks, you can use a secret, unique and random token that is embedded by the web application in all HTML forms and then verified on the server side when submitted.

Here is how you can implement this protection using Express and Jade:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var express = require('express');
var session = require('express-session');
var csrf = require('csurf');

var app = express();

app.use(session({
  secret: 'My super session secret',
  cookie: {
    httpOnly: true,
    secure: true
  }
}));

app.use(csrf());

app.use(function(req, res, next) {
  res.locals._csrf = req.csrfToken();
  next();
});
1
2
3
4
5
6
7
form(action='/account/profile', method='POST')
  input(type='hidden', name='_csrf', value=_csrf)
  div
    label(for='username') Username
    input(type='text', name='username', id='username')
  div
    input(type='submit', value='Update Profile')

This example is a little more detailed because we need to see how it all works with Express, Sessions, and our View. The csurf module requires either session middleware or cookie-parser to be initialized first. Learn more about the csurf module here and the express-session module here.

Also worth mentioning (thanks to Evan Johnson for pointing this out) is that XHR requests need to include the CSRF token. Here is an example of how you could do that.

1
2
3
4
5
6
7
var csrf_token = '<%= token_value %>';

$("body").bind("ajaxSend", function(elm, xhr, s){
  if (s.type == "POST") {
    xhr.setRequestHeader('X-CSRF-Token', csrf_token);
  }
});

Wrap up

By taking these first 4 steps, you can help secure your web application. Just using HTTPS alone is a great first step by itself. There are many more things you can and must do in order to fully secure your web applications. Think of this article as the first steps in your long journey to securing your web apps.