This document outlines the multi-layer security implementation for the Todo application.
Protection: Adds various HTTP headers to prevent common web vulnerabilities
Implementation:
- Content Security Policy (CSP) - Prevents XSS attacks by controlling resource loading
- HTTP Strict Transport Security (HSTS) - Forces HTTPS connections
- X-Frame-Options - Prevents clickjacking attacks
- X-Content-Type-Options - Prevents MIME sniffing
- X-XSS-Protection - Enables browser's XSS filter
Configuration:
app.use(helmet({
contentSecurityPolicy: { /* Custom CSP rules */ },
hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },
frameguard: { action: 'deny' },
noSniff: true,
xssFilter: true,
}));Protection: Prevents brute force attacks, API abuse, and DDoS attempts
Implementation:
- General rate limiter: 100 requests per 15 minutes per IP
- Write operations limiter: 20 requests per 15 minutes per IP
Configuration:
const generalLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
message: "Too many requests from this IP, please try again later."
});
const writeLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 20,
message: "Too many write requests, please try again later."
});Protection: Prevents NoSQL injection, XSS attacks, and invalid data
Components:
Removes or replaces characters that could be used in NoSQL injection attacks
app.use(mongoSanitize({
replaceWith: "_",
onSanitize: ({ key }) => {
console.warn(`Sanitized potentially malicious input in ${key}`);
},
}));Validates and sanitizes all user inputs on each endpoint:
- Task creation: Length limits (1-100 chars), pattern matching, HTML escaping
- Task editing: Length limits (1-100 chars), pattern matching, HTML escaping
- ID validation: MongoDB ObjectId format validation
- XSS protection: HTML entity escaping on all text inputs
Example validation:
body("task")
.trim()
.notEmpty()
.isLength({ min: 1, max: 100 })
.matches(/^[^<>]*$/)
.escape()Database-level validation as a final safeguard:
task: {
type: String,
required: true,
minlength: 1,
maxlength: 100,
match: [/^[^<>]*$/, "Task cannot contain < or > characters."],
}Protection: Prevents payload-based attacks and resource exhaustion
Implementation:
app.use(bodyParse.urlencoded({ extended: false, limit: "10kb" }));Protection: Ensures code quality and prevents committing vulnerable code
Implementation:
- Pre-commit hook runs lint-staged
- Automatically lints and formats code before commits
- Prevents committing improperly formatted or problematic code
Configuration:
"lint-staged": {
"app/**/*.{js,ejs}": [
"cd app && eslint --fix",
"cd app && prettier --write"
]
}- Defense in Depth: Multiple layers of security ensure that if one layer fails, others provide protection
- Fail Securely: Error handling that doesn't expose sensitive information
- Least Privilege: Limited request sizes and strict rate limiting
- Input Validation: All user inputs are validated and sanitized at multiple levels
- Security Headers: Modern HTTP security headers protect against common attacks
- Logging: Security events are logged for monitoring (sanitization warnings)
To verify security implementation:
- Rate Limiting Test: Send multiple rapid requests to trigger rate limits
- Input Validation Test: Try submitting tasks with special characters like
<script>alert('xss')</script> - NoSQL Injection Test: Try submitting MongoDB operators in form fields
- Size Limit Test: Try sending large payloads (>10kb)
- Header Inspection: Check response headers for security headers
- Regularly update security dependencies (helmet, express-rate-limit, etc.)
- Monitor security advisories for Node.js and npm packages
- Review and adjust rate limits based on legitimate usage patterns
- Keep validation rules in sync with business requirements
- Review security logs for suspicious patterns
Security-related packages:
helmet- HTTP security headersexpress-rate-limit- Rate limiting middlewareexpress-mongo-sanitize- NoSQL injection protectionexpress-validator- Input validation and sanitizationcookie-parser- Cookie parsing for session securityhusky- Git hooks for code qualitylint-staged- Run linters on staged files