Understanding DDoS Attacks and Protecting Your Express.js Application


What is a DDoS Attack?
A Distributed Denial of Service (DDoS) attack is a malicious attempt to disrupt the normal functioning of a targeted server, service, or network by overwhelming it with a flood of internet traffic. Unlike a regular Denial of Service (DoS) attack that comes from a single source, DDoS attacks utilize multiple compromised devices (often forming a botnet) to generate massive traffic volumes.
Common types of DDoS attacks include:
Volumetric Attacks: Overwhelm bandwidth with massive data floods
Protocol Attacks: Exploit weaknesses in network protocols
Application Layer Attacks: Target specific application vulnerabilities
These attacks can cause:
Website downtime
Slow performance
Loss of revenue
Damaged reputation
Handling DDoS Attacks in Express.js
Express.js is a popular Node.js framework for building web applications. While no system can be completely immune to DDoS attacks, you can implement several strategies to mitigate and handle them effectively.
1. Rate Limiting
Implement rate limiting to restrict the number of requests a client can make in a given timeframe:
const express = require('express');
const rateLimit = require('express-rate-limit');
const app = express();
// Apply rate limiting to all requests
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limit each IP to 100 requests per windowMs
message: 'Too many requests from this IP, please try again later.'
});
app.use(limiter);
app.listen(3000, () => {
console.log('Server running on port 3000');
});
2. Use Middleware for Request Validation
Add middleware to filter suspicious requests:
const express = require('express');
const app = express();
// Basic request validation middleware
const validateRequest = (req, res, next) => {
// Check for suspicious user agents
const userAgent = req.get('User-Agent');
if (!userAgent || userAgent.includes('bot')) {
return res.status(403).send('Access denied');
}
// Validate request size
if (req.headers['content-length'] > 10000) {
return res.status(413).send('Request too large');
}
next();
};
app.use(validateRequest);
3. Implement Request Timeout
Set timeouts to prevent slow requests from clogging your server:
const express = require('express');
const app = express();
app.use((req, res, next) => {
req.setTimeout(10000, () => {
res.status(408).send('Request timeout');
});
next();
});
4. Use a Reverse Proxy (e.g., Nginx)
Configure Nginx as a reverse proxy with additional DDoS protection:
http {
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
server {
location / {
limit_req zone=mylimit burst=20 nodelay;
proxy_pass http://localhost:3000;
}
}
}
5. Implement Caching
Use caching to reduce server load:
const express = require('express');
const apicache = require('apicache');
const app = express();
const cache = apicache.middleware;
app.use(cache('5 minutes'));
app.get('/api/data', (req, res) => {
// Your API logic here
res.json({ data: 'Some data' });
});
6. Additional Security Measures
const express = require('express');
const helmet = require('helmet');
const app = express();
// Add security headers
app.use(helmet());
// Body parser with limits
app.use(express.json({ limit: '10kb' }));
app.use(express.urlencoded({ limit: '10kb', extended: true }));
// Error handling for too many requests
app.use((err, req, res, next) => {
if (err.status === 429) {
return res.status(429).send('Too Many Requests');
}
next(err);
});
Best Practices for DDoS Protection
- Monitoring:
Set up real-time monitoring
Track traffic patterns
Set alerts for unusual activity
- Infrastructure:
Use a Content Delivery Network (CDN) like Cloudflare
Implement load balancing
Scale servers dynamically
- Preparedness:
Create an incident response plan
Maintain backups
Test your defenses regularly
Complete Example
const express = require('express');
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');
const apicache = require('apicache');
const app = express();
// Security headers
app.use(helmet());
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100
});
app.use(limiter);
// Caching
app.use(apicache.middleware('5 minutes'));
// Request validation
app.use((req, res, next) => {
req.setTimeout(10000);
if (!req.get('User-Agent')) {
return res.status(403).send('Access denied');
}
next();
});
// Routes
app.get('/', (req, res) => {
res.send('Hello World');
});
// Error handling
app.use((err, req, res, next) => {
if (err.status === 429) {
return res.status(429).send('Too Many Requests');
}
res.status(500).send('Server Error');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
Conclusion
While Express.js alone can't fully protect against large-scale DDoS attacks, combining these techniques with proper infrastructure setup can significantly improve your application's resilience. For comprehensive protection, consider:
Using cloud-based DDoS protection services
Implementing Web Application Firewalls (WAF)
Maintaining a scalable infrastructure
Regular security audits
Subscribe to my newsletter
Read articles from Antarip Chatterjee directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
