Skip to main content
Practice Problems

What are the key security best practices in Node.js?

Node.js Security Best Practices

Security is critical in any backend application. Node.js has specific attack vectors that every developer should understand and defend against.


1. Prevent Injection Attacks

SQL Injection

js
// ❌ Vulnerable β€” string concatenation const query = `SELECT * FROM users WHERE id = '${req.params.id}'`; // βœ… Safe β€” parameterized queries const result = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);

NoSQL Injection (MongoDB)

js
// ❌ Vulnerable β€” user input can be an object db.users.find({ username: req.body.username, password: req.body.password }); // Attacker sends: { "password": { "$gt": "" } } // βœ… Safe β€” validate and sanitize input const username = String(req.body.username); const password = String(req.body.password); db.users.find({ username, password: hashPassword(password) });

Command Injection

js
// ❌ Vulnerable const { exec } = require('child_process'); exec(`ls ${req.query.dir}`); // dir = "; rm -rf /" // βœ… Safe β€” use execFile with array arguments const { execFile } = require('child_process'); execFile('ls', [req.query.dir]);

2. Input Validation

Always validate and sanitize user input:

js
const Joi = require('joi'); const schema = Joi.object({ email: Joi.string().email().required(), password: Joi.string().min(8).max(128).required(), age: Joi.number().integer().min(18).max(120) }); const { error, value } = schema.validate(req.body); if (error) return res.status(400).json({ error: error.details });

3. Authentication & Authorization

PracticeImplementation
Hash passwordsbcrypt with salt rounds β‰₯ 12
Use JWT carefullyShort expiry, httpOnly cookies, refresh tokens
Rate limit loginPrevent brute force (express-rate-limit)
Use HTTPSAlways in production
js
const bcrypt = require('bcrypt'); // Hash const hash = await bcrypt.hash(password, 12); // Verify const isValid = await bcrypt.compare(password, hash);

4. HTTP Security Headers

Use helmet to set security headers:

js
const helmet = require('helmet'); app.use(helmet()); // Sets headers like: // X-Content-Type-Options: nosniff // X-Frame-Options: DENY // Strict-Transport-Security: max-age=31536000 // Content-Security-Policy: default-src 'self'

5. Dependency Security

bash
# Check for known vulnerabilities npm audit # Fix automatically where possible npm audit fix # Use Snyk for deeper analysis npx snyk test

6. Prevent Denial of Service (DoS)

js
const rateLimit = require('express-rate-limit'); const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // limit each IP to 100 requests per windowMs message: 'Too many requests' }); app.use('/api/', limiter);

Protect against ReDoS (Regular Expression DoS):

js
// ❌ Vulnerable regex β€” catastrophic backtracking const regex = /^(a+)+$/; regex.test('aaaaaaaaaaaaaaaaaaaaaaaaaaaaX'); // Hangs! // βœ… Safe β€” use safe-regex or re2 const RE2 = require('re2'); const regex = new RE2('^(a+)+$');

7. Secure Environment Variables

js
// ❌ Never hardcode secrets const secret = 'my-secret-key'; // βœ… Use environment variables const secret = process.env.JWT_SECRET; // βœ… Validate at startup if (!process.env.JWT_SECRET) { throw new Error('JWT_SECRET is required'); }

Security Checklist

CategoryAction
InputValidate all user input (Joi, class-validator)
SQL/NoSQLUse parameterized queries
AuthHash passwords with bcrypt, use JWT properly
HeadersUse helmet middleware
HTTPSEnforce TLS in production
DependenciesRun npm audit regularly
Rate limitingProtect endpoints from abuse
SecretsUse env vars, never commit to git
LoggingLog security events, never log secrets
CORSConfigure strict origin policies

Remember: Security is not a feature you add once β€” it's a mindset. Validate input, sanitize output, use least privilege, keep dependencies updated, and monitor for anomalies.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems