Tuesday, January 17, 2017

Node.js Security Tutorial

This article is the 11th part of the tutorial series called Node Hero - in these chapters, you can learn how to get started with Node.js and deliver software products using it.
In this Node.js security tutorial, you are going to learn how to defend your applications against the most common attack vectors.

Node.js Security threats

Nowadays we see almost every week some serious security breaches, like in the LinkedIn or MySpace cases. During these attacks, a huge amount of user data was leaked - as well as corporate reputations damaged.
Studies also show that security related bug tickets are open for an average of 18 months in some industries.
We have to fix this attitude. If you develop software, security is a part of your job.

Start the Node.js Security Tutorial

Let's get started, and secure our Node.js application by proper coding, tooling, and operation!

Secure Coding Style

Rule 1: Don't use eval

Eval can open up your application for code injection attacks. Try not to use it, but if you have to, never inject unvalidated user input into eval.
Eval is not the only one you should avoid - in the background each one of the following expressions uses eval:
  • setInterval(String, 2)
  • setTimeout(String, 2)
  • new Function(String)

Rule 2: Always use strict mode

With 'use strict' you can opt in to use a restricted "variant" of JavaScript. It eliminates some silent errors and will throw them all the time.
'use strict'  
delete Object.prototype  
// TypeError
var obj = {  
    a: 1, 
    a: 2 
} 
// syntax error

Rule 3: Handle errors carefully

During different error scenarios, your application may leak sensitive details about the underlying infrastructure, like: X-Powered-By:Express.
Stack traces are not treated as vulnerabilities by themselves, but they often reveal information that can be interesting to an attacker. Providing debugging information as a result of operations that generate errors is considered a bad practice. You should always log them, but never show them to the users.

Rule 4: Do a static analysis of your codebase

Static analysis of your application's codebase can catch a lot of errors. For that we suggest using ESLint with the Standard code style.

Running Your Services in Production Securely

Using proper code style is not enough to efficiently secure Node.js applications - you should also be careful about how you run your services in production.

Rule 5: Don't run your processes with superuser rights

Sadly, we see this a lot: developers are running their Node.js application with superuser rights, as they want it to listen on port 80 or 443.
This is just wrong. In the case of an error/bug, your process can bring down the entire system, as it has credentials to do anything.
Instead of this, what you can do is to set up an HTTP server/proxy to forward the requests. This can be nginx or Apache. Check out our article on Operating Node.js in Production to learn more.

Rule 6: Set up the obligatory HTTP headers

There are some security-related HTTP headers that your site should set. These headers are:
  • Strict-Transport-Security enforces secure (HTTP over SSL/TLS) connections to the server
  • X-Frame-Options provides clickjacking protection
  • X-XSS-Protection enables the Cross-site scripting (XSS) filter built into most recent web browsers
  • X-Content-Type-Options prevents browsers from MIME-sniffing a response away from the declared content-type
  • Content-Security-Policy prevents a wide range of attacks, including Cross-site scripting and other cross-site injections
In Node.js it is easy to set these using the Helmet module:
var express = require('express')  
var helmet = require('helmet')

var app = express()

app.use(helmet())  
Helmet is available for Koa as well: koa-helmet.

Rule 7: Do proper session management

The following list of flags should be set for each cookie:
  • secure - this attribute tells the browser to only send the cookie if the request is being sent over HTTPS.
  • HttpOnly - this attribute is used to help prevent attacks such as cross-site scripting since it does not allow the cookie to be accessed via JavaScript.

Rule 8: Set cookie scope

  • domain - this attribute is used to compare against the domain of the server in which the URL is being requested. If the domain matches or if it is a sub-domain, then the path attribute will be checked next.
  • path - in addition to the domain, the URL path that the cookie is valid for can be specified. If the domain and path match, then the cookie will be sent in the request.
  • expires - this attribute is used to set persistent cookies since the cookie does not expire until the set date is exceeded.
In Node.js you can easily create this cookie using the cookies package. Again, this is quite low 
-level, so you will probably end up using a wrapper, like the cookie-session.
var cookieSession = require('cookie-session')  
var express = require('express')

var app = express()

app.use(cookieSession({  
  name: 'session',
  keys: [
    process.env.COOKIE_KEY1,
    process.env.COOKIE_KEY2
  ]
}))

app.use(function (req, res, next) {  
  var n = req.session.views || 0
  req.session.views = n++
  res.end(n + ' views')
})

app.listen(3000)  
(The example is taken from the cookie-session module documentation.)

Tools to Use

Congrats, you’re almost there! If you followed this tutorial and did the previous steps thoroughly, you have just one area left to cover regarding Node.js security. Let’s dive into using the proper tools to look for module vulnerabilities!

Rule 9: Look for vulnerabilities with Retire.js

The goal of Retire.js is to help you detect the use of module versions with known vulnerabilities.
Simply install with:
npm install -g retire  
After that, running it with the retire command will look for vulnerabilities in your node_modules directory. (Also note, that retire.js works not only with node modules but with front end libraries as well.)

Rule 10: Audit your modules with the Node Security Platform CLI

nsp is the main command line interface to the Node Security Platform. It allows for auditing a package.json or npm-shrinkwrap.jsonfile against the NSP API to check for vulnerable modules.
npm install nsp --global  
# From inside your project directory
nsp check 

No comments:

Post a Comment