Quick answer
An HTTP flood is a denial-of-service attack carried out with ordinary web requests. Instead of trying to saturate the network, the attacker sends requests that are expensive for the server to answer — a search query, a login attempt, a cart operation — until the application runs out of workers, database connections or CPU. Each request is individually valid, which is what makes it hard: there is no malformed packet to drop and no bandwidth spike to notice.
Cheap to send, expensive to answer
The asymmetry is the whole attack. A GET request is a few hundred bytes and costs the attacker nothing. Answering it might mean a database query across a large table, rendering a template, and a round trip to a cache — tens of milliseconds of work.
At a few thousand requests per second, the traffic is trivial on the wire and completely overwhelming for the application. This is why an HTTP flood can take down infrastructure that would shrug off a hundred gigabits of junk packets.
| Volumetric flood | HTTP flood | |
|---|---|---|
| Measured in | Gigabits per second | Requests per second |
| What runs out | Bandwidth | Workers, DB connections, CPU |
| Visible on a traffic graph | Obviously | Often not at all |
| Stopped by | Upstream capacity | Request inspection |
| Individually valid requests | No | Yes — that is the problem |
What attackers aim at
A competent attacker does not hit your homepage, because your homepage is probably cached. They look for the endpoints that cannot be cached and cost the most.
- Search endpoints — full-text queries across large tables
- Login — deliberately slow password hashing, by design
- Cart and checkout — session state, inventory locks, no caching possible
- Filtered listing pages, where every parameter combination is a fresh query
- Any URL with a random parameter appended, which defeats caching entirely
- API endpoints that fan out into several backend calls
How it is actually detected
Since no single request is suspicious, detection works on the shape of the traffic rather than its content.
- TLS fingerprint versus claimed user-agent — a script saying it is Chrome negotiates like a script
- Header completeness and ordering, which tooling rarely reproduces exactly
- Whether the client fetches the sub-resources a browser would (CSS, images, fonts)
- Request mix: real users hit many different pages, floods hit one endpoint
- One fingerprint appearing across hundreds of unrelated addresses at once
- Whether the client can solve a challenge — most tooling has no JavaScript engine
Why rate limiting alone is not enough
The instinctive response is a per-address rate limit, and it does help against a single noisy source. Against a distributed attack it does very little: ten thousand bots making two requests a second each stay comfortably under any sane limit while delivering twenty thousand requests per second to your origin.
Rate limiting is still worth having — it stops the trivial cases and puts a ceiling on damage — but it has to be one layer among several rather than the whole defence.
What works
- Challenge ambiguous traffic instead of blocking it, so a false positive costs a second rather than a customer
- Cache what can be cached — those requests never reach the application at all
- Rate limit per route, with tight limits on expensive endpoints and loose ones elsewhere
- Score requests on several weak signals rather than trusting any single one
- Escalate only while the origin is genuinely under strain, then relax automatically
Frequently asked questions
Last updated