Express.js Security Practices
Security is not an afterthought – it's a critical part of building web applications. Express applications are vulnerable to various attacks if not properly secured. In this chapter, we'll cover essential security practices to protect your Express apps.
Common Web Vulnerabilities
| Attack | Description |
|---|---|
| SQL Injection | Malicious SQL code in user input. |
| XSS (Cross-Site Scripting) | Injecting malicious scripts into web pages. |
| CSRF (Cross-Site Request Forgery) | Forcing users to execute unwanted actions. |
| Brute Force | Repeated login attempts to guess passwords. |
Security is like an onion – it has multiple layers. Don't rely on just one security measure.
1. Use Helmet.js
Helmet helps secure your Express apps by setting various HTTP headers.
npm install helmetconst helmet = require('helmet');app.use(helmet()); <!-- This sets multiple security headers -->2. Prevent SQL Injection
Always use parameterized queries or ORMs that escape input automatically.
<!-- ❌ Vulnerable to SQL injection -->await pool.query(`SELECT * FROM users WHERE username = '${username}'`);
<!-- ✅ Safe with parameterized query -->await pool.query('SELECT * FROM users WHERE username = ?', [username]);3. Prevent XSS Attacks
Sanitize user input and escape output in templates.
<!-- Install sanitization library -->npm install express-validator
<!-- Sanitize input -->const { body, validationResult } = require('express-validator');
app.post('/comment', body('text').escape(), <!-- Escape HTML entities --> (req, res) => { <!-- Safe to use in templates --> });In EJS templates, use `<%= %>` which automatically escapes HTML. Avoid `<%- %>` for user-generated content.
4. CSRF Protection
Use the `csurf` middleware to prevent CSRF attacks.
npm install csurfconst csrf = require('csurf');const csrfProtection = csrf({ cookie: true });
app.use(csrfProtection);
app.get('/form', (req, res) => { res.render('form', { csrfToken: req.csrfToken() });});5. Secure Cookies
Always set secure options for cookies:
res.cookie('sessionId', sessionId, { httpOnly: true, <!-- Prevents XSS access via JavaScript --> secure: true, <!-- Only send over HTTPS --> sameSite: 'strict', <!-- CSRF protection --> maxAge: 3600000 <!-- Expiration -->});6. Input Validation
Never trust user input. Validate everything.
npm install express-validator
const { body, validationResult } = require('express-validator');
app.post('/user', [ body('email').isEmail().normalizeEmail(), body('password').isLength({ min: 6 }), body('age').optional().isInt({ min: 0, max: 120 }) ], (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } <!-- Process valid input --> });7. HTTPS Enforcement
Force HTTPS in production by redirecting HTTP to HTTPS.
const enforceHTTPS = (req, res, next) => { <!-- Check if request is secure --> if (req.secure || req.headers['x-forwarded-proto'] === 'https') { return next(); } <!-- Redirect to HTTPS --> res.redirect('https://' + req.headers.host + req.url);};
<!-- Use in production only -->if (process.env.NODE_ENV === 'production') { app.use(enforceHTTPS);}8. Hide Express Fingerprinting
Remove the `X-Powered-By: Express` header to make it harder for attackers to know your stack.
app.disable('x-powered-by');9. Security Headers Check
Use online tools like securityheaders.com to check your headers. Helmet sets most of these:
- Strict-Transport-Security (HSTS)
- X-Frame-Options
- X-Content-Type-Options
- Content-Security-Policy (CSP)
- Referrer-Policy
Two Minute Drill
- Use Helmet.js to set secure HTTP headers.
- Always use parameterized queries to prevent SQL injection.
- Sanitize and validate all user input.
- Use HTTP-only, secure cookies with SameSite attribute.
- Hide Express fingerprinting and enforce HTTPS in production.
Need more clarification?
Drop us an email at career@quipoinfotech.com
