Express.js Security Best Practices
Secure your Express.js application against common vulnerabilities. Learn about CORS, helmet, input validation, and security headers.
Overview
Security is paramount in web applications. Express.js apps need protection against common vulnerabilities like XSS, CSRF, and injection attacks.
Common Vulnerabilities
- **XSS (Cross-Site Scripting)**: Injecting malicious scripts - **CSRF (Cross-Site Request Forgery)**: Unauthorized commands from trusted users - **SQL/NoSQL Injection**: Malicious database queries - **Directory Traversal**: Accessing unauthorized files
Security Middleware
Use packages like Helmet to set secure HTTP headers. It helps protect against common attacks with minimal configuration.
Input Validation
Never trust user input. Validate and sanitize all data before processing.
HTTPS and CORS
Always use HTTPS in production. Configure CORS properly to control which origins can access your API.
Code Examples
Helmet Security Headers
const helmet = require('helmet');
const cors = require('cors');
// Apply security headers
app.use(helmet());
// Configure CORS
app.use(cors({
origin: process.env.ALLOWED_ORIGINS?.split(',') || 'http://localhost:3000',
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 86400 // 24 hours
}));
// Prevent parameter pollution
const hpp = require('hpp');
app.use(hpp());
// Limit request body size
app.use(express.json({ limit: '10kb' }));Input Validation with Joi
const Joi = require('joi');
const userSchema = Joi.object({
name: Joi.string().min(2).max(50).required(),
email: Joi.string().email().required(),
password: Joi.string()
.min(8)
.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/)
.required()
.messages({
'string.pattern.base': 'Password must contain uppercase, lowercase, and number'
})
});
const validate = (schema) => {
return (req, res, next) => {
const { error, value } = schema.validate(req.body, { abortEarly: false });
if (error) {
return res.status(400).json({
status: 'fail',
errors: error.details.map(d => d.message)
});
}
req.body = value; // Use sanitized value
next();
};
};
app.post('/register', validate(userSchema), registerController);Sanitize MongoDB Queries
const mongoSanitize = require('express-mongo-sanitize');
const xss = require('xss-clean');
// Prevent NoSQL injection
app.use(mongoSanitize());
// Prevent XSS attacks
app.use(xss());
// Custom sanitization for specific fields
const sanitizeInput = (req, res, next) => {
if (req.body) {
// Remove any $ or . from object keys
const sanitize = (obj) => {
for (let key in obj) {
if (key.startsWith('$') || key.includes('.')) {
delete obj[key];
} else if (typeof obj[key] === 'object') {
sanitize(obj[key]);
}
}
};
sanitize(req.body);
}
next();
};
app.use(sanitizeInput);Frequently Asked Questions
Is helmet enough for security?
How do I protect against CSRF attacks?
Should I store sensitive data in environment variables?
Need expert help with Express.js?
Our team at Slashdev.io builds production-ready Express.js applications.