Security is critical for production applications. This guide covers essential security practices for Express apps.
Use Helmet
Helmet helps secure Express apps by setting various HTTP headers.
Use Helmet middleware
const helmet = require ( 'helmet' );
const express = require ( 'express' );
const app = express ();
app . use ( helmet ());
Helmet sets multiple security headers including Content-Security-Policy, X-DNS-Prefetch-Control, X-Frame-Options, and more.
Prevent SQL Injection
Always use parameterized queries or prepared statements:
Bad - Vulnerable to SQL Injection
Good - Parameterized Query
Good - ORM (Sequelize)
const userId = req . params . id ;
const query = 'SELECT * FROM users WHERE id = ' + userId ; // DON'T DO THIS!
db . query ( query );
Never concatenate user input directly into SQL queries. Always use parameterized queries.
Prevent Cross-Site Scripting (XSS)
Escape output in templates
Always escape user-generated content: <!-- EJS - Use <%= not <%- -->
< p > Welcome < %= username %> </ p >
<!-- Pug - Automatic escaping -->
p Welcome #{username}
Sanitize input
npm install express-validator
const { body , validationResult } = require ( 'express-validator' );
app . post ( '/user' ,
body ( 'email' ). isEmail (). normalizeEmail (),
body ( 'name' ). trim (). escape (),
( req , res ) => {
const errors = validationResult ( req );
if ( ! errors . isEmpty ()) {
return res . status ( 400 ). json ({ errors: errors . array () });
}
// Process valid data
}
);
Set Content-Security-Policy
app . use ( helmet . contentSecurityPolicy ({
directives: {
defaultSrc: [ "'self'" ],
scriptSrc: [ "'self'" , "trusted-cdn.com" ],
styleSrc: [ "'self'" , "'unsafe-inline'" ],
imgSrc: [ "'self'" , "data:" , "https:" ]
}
}));
Use HTTPS
Always use HTTPS in production to encrypt data in transit.
const https = require ( 'https' );
const fs = require ( 'fs' );
const express = require ( 'express' );
const app = express ();
const options = {
key: fs . readFileSync ( 'private-key.pem' ),
cert: fs . readFileSync ( 'certificate.pem' )
};
https . createServer ( options , app ). listen ( 443 );
For production, use a reverse proxy (nginx, Apache) or service (Cloudflare, AWS) to handle HTTPS.
Secure Session Management
Production Session Config
Development Session Config
const session = require ( 'express-session' );
const RedisStore = require ( 'connect-redis' ). default ;
const { createClient } = require ( 'redis' );
const redisClient = createClient ();
redisClient . connect (). catch ( console . error );
app . use ( session ({
store: new RedisStore ({ client: redisClient }),
secret: process . env . SESSION_SECRET ,
resave: false ,
saveUninitialized: false ,
cookie: {
secure: true , // Require HTTPS
httpOnly: true , // Prevent client-side access
maxAge: 3600000 , // 1 hour
sameSite: 'strict' // CSRF protection
}
}));
Use a strong, random session secret and store it in environment variables. Never commit secrets to version control.
Rate Limiting
Prevent brute-force attacks with rate limiting:
npm install express-rate-limit
const rateLimit = require ( 'express-rate-limit' );
// General rate limiter
const limiter = rateLimit ({
windowMs: 15 * 60 * 1000 , // 15 minutes
max: 100 , // Limit each IP to 100 requests per windowMs
message: 'Too many requests from this IP'
});
app . use ( '/api/' , limiter );
// Stricter rate limit for auth endpoints
const authLimiter = rateLimit ({
windowMs: 15 * 60 * 1000 ,
max: 5 ,
message: 'Too many login attempts'
});
app . post ( '/login' , authLimiter , ( req , res ) => {
// Handle login
});
Prevent NoSQL Injection
Sanitize MongoDB queries:
npm install express-mongo-sanitize
const mongoSanitize = require ( 'express-mongo-sanitize' );
app . use ( mongoSanitize ());
CSRF Protection
Protect against Cross-Site Request Forgery:
const csrf = require ( 'csurf' );
const csrfProtection = csrf ({ cookie: true });
app . use ( csrfProtection );
app . get ( '/form' , ( req , res ) => {
res . render ( 'form' , { csrfToken: req . csrfToken () });
});
app . post ( '/submit' , ( req , res ) => {
// CSRF token automatically validated
res . send ( 'Success' );
});
< form method = "POST" action = "/submit" >
< input type = "hidden" name = "_csrf" value = "{{csrfToken}}" >
< button type = "submit" > Submit </ button >
</ form >
Secure Password Storage
Never store passwords in plain text:
const bcrypt = require ( 'bcrypt' );
const saltRounds = 10 ;
// Hash password
app . post ( '/register' , async ( req , res ) => {
const hashedPassword = await bcrypt . hash ( req . body . password , saltRounds );
// Store hashedPassword in database
});
// Verify password
app . post ( '/login' , async ( req , res ) => {
const user = await User . findOne ({ email: req . body . email });
const match = await bcrypt . compare ( req . body . password , user . password );
if ( match ) {
// Password correct
} else {
// Password incorrect
}
});
Environment Variables
Never commit secrets or API keys to version control. Use environment variables.
require ( 'dotenv' ). config ();
const dbPassword = process . env . DB_PASSWORD ;
const apiKey = process . env . API_KEY ;
const sessionSecret = process . env . SESSION_SECRET ;
DB_PASSWORD=your_secure_password
API_KEY=your_api_key
SESSION_SECRET=your_session_secret
NODE_ENV=production
Validate all user input:
const { body , param , validationResult } = require ( 'express-validator' );
app . post ( '/user/:id' ,
param ( 'id' ). isInt (),
body ( 'email' ). isEmail (). normalizeEmail (),
body ( 'age' ). optional (). isInt ({ min: 0 , max: 120 }),
body ( 'username' ). trim (). isLength ({ min: 3 , max: 30 }). isAlphanumeric (),
( req , res ) => {
const errors = validationResult ( req );
if ( ! errors . isEmpty ()) {
return res . status ( 400 ). json ({ errors: errors . array () });
}
// Process validated data
}
);
Dependency Security
Audit dependencies regularly
Keep dependencies updated
Use automated tools
npm install -g snyk
snyk test
const express = require ( 'express' );
const app = express ();
// Disable X-Powered-By header
app . disable ( 'x-powered-by' );
// Or use Helmet to set multiple headers
const helmet = require ( 'helmet' );
app . use ( helmet ());
Security Checklist
Essential Security Measures