Prevent Slow Connection DoS on Node.js Server
Denial of Service (DoS) attacks exploiting slow client connections, such as Slowloris, can easily crash a Node.js server by keeping connection pools open and exhausting system resources. This article provides a direct guide on how to protect your Node.js application by configuring HTTP timeouts, implementing rate limiting, restricting payload sizes, and deploying reverse proxies.
Configure HTTP Server Timeouts
By default, Node.js HTTP servers can be vulnerable to slow-write attacks if timeouts are not strictly managed. You should explicitly configure timeouts on your server instance to automatically terminate inactive or excessively slow connections.
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Secure Server');
});
// Set the timeout limits in milliseconds
server.headersTimeout = 5000; // 5 seconds to receive request headers
server.requestTimeout = 10000; // 10 seconds to receive the entire request
server.keepAliveTimeout = 5000; // 5 seconds of inactivity before closing keep-alive
server.timeout = 15000; // 15 seconds max connection lifetime
server.listen(3000);Implement Rate Limiting
Rate limiting prevents a single IP address from opening too many
concurrent connections or making too many requests within a short
timeframe. If you are using Express, you can use the
express-rate-limit middleware to mitigate abuse.
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limit each IP to 100 requests per window
message: 'Too many requests from this IP, please try again later.'
});
app.use(limiter);Limit Request Body Sizes
Attackers can slow down a server by sending massive payloads at a rate of just a few bytes per second. Restricting the acceptable size of incoming requests ensures the server rejects bloated payloads immediately.
Using Express built-in middleware, you can set strict body limits:
const express = require('express');
const app = express();
app.use(express.json({ limit: '10kb' })); // Limit JSON bodies to 10KB
app.use(express.urlencoded({ extended: true, limit: '10kb' }));Deploy a Reverse Proxy
The most robust defense against slow connection attacks is placing a reverse proxy, such as Nginx, or a cloud security provider like Cloudflare, in front of your Node.js application.
A reverse proxy is highly optimized to handle thousands of concurrent connections. It buffers the incoming slow client requests completely before passing them to your Node.js server, shielding Node.js from the slow connection overhead entirely.
For example, in Nginx, you can configure buffer and timeout directives:
client_body_timeout 10s;
client_header_timeout 10s;
keepalive_timeout 5s;
send_timeout 10s;