Web security is critical for protecting user data and maintaining trust. This guide covers essential security practices every developer should implement.
1. HTTPS Everywhere
// Express.js HTTPS setup
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.cert')
};
https.createServer(options, app).listen(443);
// Redirect HTTP to HTTPS
app.use((req, res, next) => {
if (!req.secure) {
return res.redirect(301, "https://req.headers.hostreq.url");
}
next();
});
2. Prevent SQL / NoSQL Injection
< pre >// ❌ Vulnerable (SQL)
const query = "SELECT * FROM users WHERE email = 'email'";
// ✅ Safe (Parameterized queries)
const query = 'SELECT * FROM users WHERE email = ?';
db.query(query, [email]);
// ❌ Vulnerable (MongoDB)
User.find({ email: email });
// ✅ Safe (MongoDB with validation)
const email = req.body.email;
if (!validator.isEmail(email)) {
throw new Error('Invalid email');
}
User.find({ email: email }); >
3. Prevent XSS(Cross - Site Scripting)
< pre >// Sanitize user input
const DOMPurify = require('dompurify');
// Server-side sanitization
const clean = DOMPurify.sanitize(userInput);
// Set Content Security Policy (CSP)
app.use((req, res, next) => {
res.setHeader('Content-Security-Policy',
"default-src 'self'; script-src 'self' 'unsafe-inline' https://trusted-cdn.com"
);
next();
});
// Escape output automatically (React does this)
// Avoid dangerouslySetInnerHTML without sanitization>
4. Prevent CSRF(Cross - Site Request Forgery)
< pre >const csrf = require('csurf');
const cookieParser = require('cookie-parser');
app.use(cookieParser());
app.use(csrf({ cookie: true }));
// Include CSRF token in forms
app.get('/form', (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});
// In form (with hidden input)
& lt;input type = "hidden" name = "_csrf" value = "{{csrfToken}}" & gt; >
5. Secure Authentication
< pre >const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
// Hash passwords (never store plain text)
const saltRounds = 12;
const hashedPassword = await bcrypt.hash(password, saltRounds);
// Verify password
const isValid = await bcrypt.compare(inputPassword, storedHash);
// JWT with expiration
const token = jwt.sign(
{ userId: user.id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '1h', algorithm: 'RS256' }
);
// Strong password requirements
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*d)(?=.*[@$!%*?&])[A-Za-zd@$!%*?&]{8,}$/; >
6. Rate Limiting
< pre >const rateLimit = require('express-rate-limit');
// General rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
app.use(limiter);
// Strict limits for auth endpoints
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // 5 attempts per 15 minutes
skipSuccessfulRequests: true
});
app.use('/api/auth/login', authLimiter); >
7. Security Headers
< pre >const helmet = require('helmet');
app.use(helmet()); // Sets many security headers
// Or configure manually
app.use((req, res, next) => {
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-XSS-Protection', '1; mode=block');
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
next();
}); >
8. Secure Dependencies
< pre ># Audit dependencies for vulnerabilities
npm audit
npm audit fix
# Regular updates
npm update
# Use Snyk or Dependabot for automated scanning
snyk test
snyk monitor
# Lock dependency versions(package - lock.json)
# Use npm ci instead of npm install in CI / CD < /code>
Security Checklist for Production
□ Use HTTPS with valid certificates
□ Enable CSP(Content Security Policy)
□ Set secure HTTP headers
□ Hash passwords(bcrypt, scrypt, or argon2)
□ Implement rate limiting
□ Validate and sanitize all user input
□ Use parameterized queries / ORMs
□ Implement proper authentication & authorization
□ Store secrets in environment variables(never in code)
□ Use CSRF tokens for state - changing operations
□ Keep dependencies updated
□ Enable 2FA for admin accounts
□ Implement logging for security events
□ Regular security audits and penetration testing
□ Backup data regularly
< h2 > Common Security Mistakes to Avoid >
< ul >
Storing passwords in plain text
< li > Trusting user input without validation >
< li > Disabling security features for convenience >
< li > Not updating dependencies >
< li > Exposing error details in production >
< li > Using weak password requirements >
< li > Not implementing proper session management >
< li > Hardcoding secrets in source code >
< h2 > Conclusion >
< p > Security should be baked into your development process, not an afterthought.Start with HTTPS, input validation, and proper authentication, then layer additional protections based on your application's needs.>