How it works
Clients open connections and then send headers or body data at a trickle, or repeatedly begin expensive cryptographic handshakes without completing useful sessions. Each connection is nearly free for the attacker and holds a scarce server resource for as long as timeouts permit.
Slowness as the weapon
Most denial-of-service intuition is about volume, which makes this family counter-intuitive: the attack succeeds by sending as little as possible, as slowly as possible.
The resource under attack is concurrency. A server that dedicates a worker, thread or connection slot to each in-flight request has a finite number of them, and that number is usually far smaller than its bandwidth would suggest. If each slot can be held open by a client sending one byte every few seconds, the arithmetic strongly favours the attacker — a few hundred connections from a single machine can exhaust a server that comfortably handles thousands of ordinary requests per second.
Bandwidth graphs show nothing. Request counts show nothing, because the requests never complete. The service is unreachable while every volumetric metric appears healthy, which is why these attacks are frequently misdiagnosed as an application fault.
The three slow variants
Slow headers is the original form. The client opens a connection and sends a request line followed by headers, one at a time, never sending the blank line that signals completion. The server holds the connection open waiting for a request that will never finish arriving.
Slow body inverts it. The client sends complete headers declaring a body of some length, then delivers that body a few bytes at a time. The request is well formed and the server is obliged to wait, because a slow upload is indistinguishable from a legitimate client on a poor connection.
Slow read attacks the response direction. The client makes a normal request and then reads the response extremely slowly, advertising a tiny receive window. The server must hold the response and its associated buffers until the client accepts it.
All three exploit the same generosity: protocol timeouts designed to accommodate genuinely slow legitimate clients.
TLS handshake exhaustion
The cryptographic variant targets connection setup rather than request handling. A TLS handshake requires meaningful computation from the server, and that cost is asymmetric — an attacker can begin handshakes far more cheaply than the server can complete them, particularly by renegotiating or by abandoning each handshake after the expensive step.
The signature is edge or origin CPU rising sharply before any application traffic appears, together with a collapse in session resumption rate. Normal client populations resume a substantial fraction of sessions; attack traffic never does, because resumption requires prior state the attacker has no reason to keep.
Modern TLS versions reduced the asymmetry, and session resumption removes most of the cost for returning clients. The structural answer is to terminate TLS on infrastructure provisioned for handshake volume — a CDN or dedicated edge — rather than on origin servers sized for application work.
Why architecture beats tuning
Timeouts are the direct control and there is a genuine tension in setting them. Tight deadlines cut off attacks and also cut off real users on poor mobile connections, and the users most affected are the ones already having the worst experience.
The architectural answer removes most of the tension. Put a buffering reverse proxy or CDN in front of the origin and require it to receive a complete request before opening a connection backward. Slow clients then occupy a slot on infrastructure designed to hold enormous numbers of mostly idle connections cheaply, and the origin — where concurrency is scarce — only ever sees complete requests it can answer immediately.
This is the same principle that defeats SYN floods, applied one layer up: create the expensive state as late as possible, on the component built to absorb it.
Where an origin must be directly exposed, an event-driven server holding connections without dedicating a thread to each is far more resilient than a worker-per-connection model, though it is not immune — memory and file descriptors remain finite.
Practical settings
Concrete controls, roughly in order of effectiveness:
- A hard deadline for receiving complete request headers, measured in seconds rather than minutes.
- A minimum transfer rate for request bodies, with connections falling below it dropped rather than merely timed out at the end.
- An absolute request lifetime, so no single request can occupy a slot indefinitely regardless of activity.
- Per-address and per-account concurrent connection caps, sized well below total capacity.
- Body size limits enforced at the edge, so an oversized upload is rejected before it consumes anything.
- Handshake rate limits per client, and session resumption enabled so legitimate returning clients are not penalised by them.
Also known as
What defenders may observe
- Many long-lived requests that never complete
- High connection count with negligible bandwidth
- Workers or threads busy while throughput is near zero
- Header or body timeouts repeatedly approached but not exceeded
- Handshake rate and failure rate spike while session resumption falls
Prevention and mitigation
- Enforce strict header, body and idle timeouts — deadlines are the core control
- Require a minimum data rate and drop connections that fall below it
- Cap concurrent connections per client address and per account
- Terminate at an edge or proxy that buffers a complete request before contacting the origin
- Enable session resumption and keep TLS stacks current
- Rate-limit handshakes at the edge and terminate TLS on capacity built for it
Initial response priorities
- Activate application-aware edge controls and origin shielding.
- Identify the expensive route, query or protocol behavior.
- Challenge, rate-limit or shed abusive work while preserving normal users.
Use your approved incident-response plan and adapt decisions to your environment. This is educational guidance, not a substitute for live incident leadership.