Node.js + Express.js Security Best Practices

Intended as a security checklist for production ready applications. stuff like security dependencies, best practices, and hanging fruits.

IDE Recommendations

eslint-plugin-security

Snyk IDE

Up to date versions

https://expressjs.com/en/advanced/best-practice-security.html#dont-use-deprecated-or-vulnerable-versions-of-express

not really need Snyk, just make sure express npm, Node doesn’t use out-of-date versions

use

Snyk audit

Using TLS

https://expressjs.com/en/advanced/best-practice-security.html#use-tls

Make sure the application uses TLS, HTTPS,

  • verify certificate, and renewal automation scripts

  • Test production website against the CA

Use of Helmet

https://expressjs.com/en/advanced/best-practice-security.html#use-helmet

https://www.securecoding.com/blog/using-helmetjs/

https://geshan.com.np/blog/2021/01/nodejs-express-helmet/

Online Checker:http://cyh.herokuapp.com/cyh.

  • 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

  • helmet.contentSecurityPolicy which sets the Content-Security-Policy header. This helps prevent cross-site scripting attacks among many other things.

  • helmet.hsts which sets the Strict-Transport-Security header. This helps enforce secure (HTTPS) connections to the server.

  • helmet.frameguard which sets the X-Frame-Options header. This provides clickjacking protection.

const helmet = require('helmet')
app.use(helmet())

Without helmet use: app.disable('x-powered-by')

# nginx.conf

add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Content-Security-Policy "default-src 'self'";

JWT

Most secure (though not always practical) use of JWT tokens:

General Best Practice

  • tokens used for authorization, but not session management

  • short lived (few minutes)

  • expected to be used once (confirm authentication/authorization and get a session ID)

  • memory-only JWT token handling

Applied Best Practice

  • algorithm must be explicitly selected

  • validate all signatures

  • key generating libraries should rely on cryptographic-quality pseudo-random number generators (PRNGs

  • Use Different Validation Rules For Each Token

    • rather than using the same private key for signing all kinds of tokens, consider using different private keys for each subsystem of your architecture

  • Use The typ Claim To Separate Types Of Tokens

Use cookies securely

https://expressjs.com/en/advanced/best-practice-security.html#use-cookies-securely

  • express-session that replaces express.session middleware built-in to Express 3.x.

  • cookie-session that replaces express.cookieSession middleware built-in to Express 3.x.

const session = require('express-session')
app.set('trust proxy', 1) // trust first proxy
app.use(session({
  secret: 's3Cur3',
  name: 'sessionId'
}))

Rate limiting

https://expressjs.com/en/advanced/best-practice-security.html#prevent-brute-force-attacks-against-authorization

Baseline for limiting:

  1. Number of consecutive failed attempts by the same user name and IP address.

  2. Number of failed attempts from an IP address over some long period of time. For example, block an IP address if it makes 100 failed attempts in one day.

SQL injection, using parameterized queries or prepared statements

Lookup ‘Database.Query(’

mitigation

https://www.npmjs.com/package/pg

var q = 'SELECT name FROM books WHERE id = $1';
client.query(q, ['3'], function(err, result) {});

CSURF

https://www.npmjs.com/package/csurf

protection against CSRF

Regex

https://www.npmjs.com/package/safe-regex

User input Filtering and Sanitization

express-validator and express-sanitize-input

https://www.npmjs.com/package/string-sanitizer

var sanitizer = require('sanitize')();

 var name = sanitizer.value(req.name, 'string');

Last updated