DEV Community

Cover image for How to Secure your NodeJs Express JavaScript Application - part 1
SmartScanner
SmartScanner

Posted on • Originally published at thesmartscanner.com

How to Secure your NodeJs Express JavaScript Application - part 1

Express is a fast, unopinionated, and minimalist web framework for Node.js. It has been a de facto choice for creating a web-server application in Node.js. Read these series if you want to use Express in your application.

Let's see how you can make Express more secure.

Use Updated Express Version (and any other npm package)

Old versions of Express have vulnerabilities like Path traversal (CVE-2017-14849). The best practice is to use the latest stable packages to mitigate such vulnerabilities. You can use the npm audit command to find out known vulnerabilities in your Nodejs application. Then you can fix them by running the npm audit fix command. Make sure to get 0 vulnerabilities in the report of the npm audit command.

Secure your HTTP Headers

Proper HTTP headers can prevent security vulnerabilities like Cross-Site Scripting, Click-jacking, Packet sniffing and, information disclosure. It's better not to use Express with its default HTTP headers.
Try the Helmet npm package for hardening the HTTP headers of your Express project. Below is a sample code.

const express = require("express");
const helmet = require("helmet");

const app = express();

app.use(helmet());

// ...
Enter fullscreen mode Exit fullscreen mode

Read the Complete guide to HTTP Headers for more detailed information about HTTP Headers security.

Validate Input

Hackers should find a way into your application and, request parameters are their first choice. All the injection vulnerabilities like SQL Injection, Command Injection, Expression Language injection, and many others occur when unvalidated user input is directly used in performing tasks.

Consider below code which gets your name in the name query parameter and displays it.

const express = require('express')
const app = express()

app.get('/', function (request, response) {
 response.send('Hello ' + request.query.name)
})

app.listen(3000)
Enter fullscreen mode Exit fullscreen mode

If you send a request like http://localhost:3000/?name[foo]=bar then you will receive an Object instead of a String name. This is an attack known as HTTP Parameter Pollution (HPP). It can be very scary when working with a no-SQL database like MongoDB.

Before processing any request parameter, validate the following:

  • Input type (either String, Number, Boolean, etc.)
  • Input boundaries: Check range for numbers, length, and acceptable characters for strings
  • Input format: Check for input patterns like emails, IP addresses, etc.

You can use hpp npm package for preventing HPP attacks explained above.

Input validation is a broad topic. It can be very tricky especially dealing with rich user content. You can read this article for an in-depth review.

Sanitize Output

Below sample code exposes a Cross-Site scripting (XSS) vulnerability.

const express = require('express')
const app = express()

app.get('/', function (request, response) {
 response.send('Hello ' + request.query.name)
})

app.listen(3000)
Enter fullscreen mode Exit fullscreen mode

If you run the application and open http://localhost:2000/?name=<script>alert(1)</script> URL, the alert(1) JavaScript code will be executed. XSS bug allows an attacker to run any client-side code to steal session tokens, passwords or display wrong information.

Cross-Side Scripting Vulnerability

To prevent the XSS you have to use proper encoding before rendering input parameters in the response. You can use node-esapi or escape-html

Below code is a fix for the above XSS:

const express = require('express')
var ESAPI = require('node-esapi');
const app = express()

app.get('/', function (request, response) {
 encodedName = ESAPI.encoder().encodeForHTML(request.query.name)
 response.send('Hello ' + encodedName)
})

app.listen(3000)
Enter fullscreen mode Exit fullscreen mode

Use Anti CSRF

Processing form data and performing actions only by relying on the form data will cause a Cross-Site Request Forgery (CSRF).
If the same request data (either form data or URL query) causes the same action on your application then you have a CSRF issue. It gets serious when the action is sensitive like, creating a new user or deleting data.

Attackers use CSRF to perform actions on behalf of an authorized user while the user is unaware of this action. Below sample code is an example that kills the app by a CSRF.

const express = require('express')
const app = express()

app.get('/', function (request, response) {
 response.send('<h1>Admin Panel</h1><a href=/kill>kill</a>')
})

app.get('/kill', function (request, response) {
 process.exit()
})

app.listen(2000)
Enter fullscreen mode Exit fullscreen mode

You might wonder that adding cookie-based session management cannot prevent CSRF because Cookies are automatically sent by browsers. To prevent CSRF you should send random tokens within each request and validate the existence of the CSRF token before processing the request.

You can use the csurf npm package for integrating CSRF prevention in your Express application.

In next article we will see how to prevent brute force attacks, command execution and information disclosure vulnerabilities.

Top comments (2)

Collapse
 
kostyatretyak profile image
Костя Третяк

It has been a de facto choice for creating a web-server application in Node.js.

In 2010-2014 - yes, but not in 2022.

Collapse
 
smartscanner profile image
SmartScanner

Thanks for your comment. I'm aware of many other options available nowadays (fastify, Nest, SailsJS, koa, etc.) But I think Express is still quite popular to call it de facto.