ExpressJS - Security Practices



ExpressJS is an unopinionated. ExpressJS framework is highly flexible with a simple, minimalistic design principles. We can quickly setup server, define routes and start handling http requests with very few lines of code. It is very important to secure our server in production. Following are the security best practices for an Express Application one should consider while running application in production.

Use latest stable version of Express

We should never use deprecated or vulnerable versions of express in production. You can follow Official Express Security Updates Page to ensure if any listed vulnerable express version is being used. Express 2.x and 3.x are no longer maintained and there is no new security patch or performance fix is planned for them. You can move to express 4.x or the latest stable version.

User Inputs should be sanitized

All types of user inputs should be validated and handled. Sanitizing user input helps preventing injection attacks.

const express = require('express');
const app = express();
const { body, validationResult } = require('express-validator');

app.post('/login',
  body('username').isAlphanumeric(),
  body('email').isEmail(),
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }

    // if there is no error, proceed
});

Use helmet to secure express apps

Helmet is a security library and can protect app from well known vulnerabilities by setting http-headers appropriately. helmet is a collectio of middleware functions to set security related http response headers.

  • helmet.contentSecurityPolicy− Sets Content-Security-Policy header to prevent cross-site scripting attacks.

  • helmet.hsts− Sets Strict-Transport-Security to ensure https based secure connections to the server.

  • helmet.frameguard− Sets X-Frame-Options to provide Clickjacking protection

Install helmet

npm install --save helmet

Use helmet

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

app.use(helmet());

Use Secure Dependencies Only

Use npm to analyze the dependency tree and figure out any vulnerable dependency.

npm audit

Use Snyk

Snyk is a better alternative to check vulnerabilities against Snyk's open source vulnerability database.

Install snyk.

npm install -g snyk

test application for vulnerabilities.

synk test

Rate Limiting

Rate limiting limits the number of requests that a user can make within given time frame. This helps to prevent brute force attacks.

Use express-rate-limit middleware.

const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
});

app.use(limiter);

Use HTTPS

HTTPS is a secure connection protocol over http. Http traffic can be intercepted. Use https module to read SSL/TLS certificates to make a secure server.

const https = require('https');
const fs = require('fs');
const app = require('express')();

const options = {
  key: fs.readFileSync('key.pem'),
  cert: fs.readFileSync('cert.pem')
};

https.createServer(options, app).listen(443);

Use Secure and HTTP Only Cookies

During session management, always set cookies as secure and http-only to prevent client side scripts to access your cookies.

const session = require('express-session');

app.use(session({
  secret: 'secret-code',
  cookie: {
    secure: true,
    httpOnly: true,
  },
  // ...
}));

Error handling

Always handle error and return user a custom message instead of default error handling. Middleware should manage errors properly and avoid revealing stack trace to the users.

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Server Error!');
});

Apart from these security practices, you should follow best coding practices as specified by your organization. Ensure code reviews, monitorings, reviews processes are followed properly.

Advertisements