HTTP flood: valid requests that take a whole site down

An HTTP flood sends ordinary requests in quantities the application cannot serve. Each is well formed, arrives over a completed connection, and asks for something a real visitor might ask for. There is no malformed input to reject and no signature to match, which makes this the hardest family to filter and the one where filtering applies.

Section Attacks Updated Measures four

Quick facts

Layer
Application (7)
Vector
Large numbers of valid requests, often to a few paths
Goal
Exhaust processing, memory, or the database behind the site
In your logs
Logs fill; response times climb before failures start
Does a WAF stop it?
Yes, by limiting and pricing requests rather than by recognising bad ones

That qualifier is the whole subject of this page. Defence works on aggregate behaviour, because no individual request is distinguishable from one a customer would send.

Two shapes, different costs

Requests that only read are the cheaper form for the sender: no body to construct, no session to maintain. Their effectiveness depends entirely on choosing paths that cost you something, which is why an attack on a search or a filtered listing does more damage than one on a static page.

Requests that submit are more expensive for both sides. They force parsing, validation, and often a write, and writes are the operations least able to be scaled away by caching or read replicas. A modest rate against a submission endpoint can outweigh a much larger rate against a page that only reads.

RATE IS NOT THE MEASURE — COST PER REQUEST IS REQUESTS THAT ONLY READ RATE COST EACH COSTS YOU REQUESTS THAT SUBMIT RATE COST EACH COSTS YOU // writes are what caching and read replicas cannot scale away
// a modest rate against a write outweighs a large one against a read

The choice between them tells you something about the sender's intent: a flood aimed at reads is usually about volume, while one aimed at writes is usually about finding your most expensive operation.

Why per-request filtering fails

A request carries a method, a path, headers, and possibly a body. Every one of those fields can hold exactly what a browser would send, because there is nothing preventing it.

One consequence is where most defensive effort is wasted: any rule that describes what a bad request looks like will either miss traffic that copies a browser or block customers whose requests happen to match. The distinguishing information does not exist inside a single request. It exists across many of them.

THE DISTINGUISHING INFORMATION IS NOT INSIDE A REQUEST ONE REQUEST — FIELD BY FIELD METHOD PATH HEADERS BODY EVERY FIELD CAN HOLD EXACTLY WHAT A BROWSER WOULD SEND A REAL POPULATION, OVER TIME — IRREGULAR BY NATURE A FLOOD, OVER TIME — EVEN INTERVALS, IDENTICAL EVERYTHING // the evidence is in the shape of traffic rather than in its contents
// no rule about one request survives a sender who copies a browser

What the aggregate shows

The evidence is in the shape of traffic rather than in its contents.

Illustrative access log extract
# Illustrative access log extract; values are shape, not measurements.
# Addresses per RFC 5737, host per RFC 2606.

198.51.100.x  GET /search?q=... HTTP/1.1  200  ua="<identical string>"  ref="-"
198.51.100.x  GET /search?q=... HTTP/1.1  200  ua="<identical string>"  ref="-"
203.0.113.x   GET /search?q=... HTTP/1.1  200  ua="<identical string>"  ref="-"
203.0.113.x   GET /  HTTP/1.1             200  ua="<varied>"  ref="example.com"

Four properties separate the two kinds of line above.

Path concentration. Real populations spread across a site. A flood concentrates, usually on whatever is expensive.

Uniform timing. Human traffic is irregular: people read, pause, and leave. Generated traffic tends toward even intervals unless deliberately varied.

Missing context. Requests arriving without the accompanying assets a page would load, or without the referrer chain that browsing produces, are not browsing.

Population uniformity. A client base that all announces itself identically, or that all appeared within the same minute, is not a client base.

The signal everyone over-trusts

A single repeated User-Agent string looks conclusive and is not.

That header is set by whoever sends the request, so it proves nothing on its own: it can copy a current browser exactly, and it frequently does. Meanwhile a genuine population contains large groups sharing identical strings, because that is what a popular browser version looks like.

Treat it as one weak input among several. Blocking on it alone is a decision that removes real visitors and stops working the moment the sender changes one line.

Where the traffic comes from

Requests at scale usually originate from many compromised or rented machines rather than from one place, which is why source-based blocking runs out quickly: each address contributes little, and there are many.

That property is the reason limits work better per client than in aggregate, and the reason challenges matter: they ask each source to spend something, and the economics of the attack depend on each source being cheap.

Mitigation by layer

Four measures, and unlike the other families these are yours to apply.

Limit per endpoint, not just per site. The expensive path deserves a tighter allowance than the cheap one, and a single global rate either throttles normal browsing or leaves the expensive path unprotected.

Challenge before blocking. Asking a client to demonstrate it is a browser separates populations without denying anyone outright, and it costs far less in false positives than a block.

Cache what can be cached. A request served from cache removes the lever entirely. Attacks concentrate on what cannot be cached precisely because of this.

Bound the expensive operations. Limiting what a search may return or what a report may span reduces the cost per request, which changes the rate at which an attack becomes viable.

When the flood is your own success

Check this before any of the above: the response differs and the symptoms do not.

A campaign that worked, a link that spread, or a partner sending traffic they did not warn you about all produce a sudden concentration of requests on a few paths. So does a search engine indexing a section it had not seen before. Each looks like an attack in every graph you have, and each is revenue rather than an emergency.

Two checks usually settle it. Look at whether the traffic converts or behaves like people once it arrives: real visitors load assets, follow links, and leave in a distribution. And look at whether the sources have histories, since a population that existed yesterday is different from one that appeared at once.

Check this before applying anything below

The reason to check first is that the measures on this page work equally well against customers. A limit that ends an attack also ends a launch, and the graph looks the same either way.

The cost of getting it wrong

Every measure here can refuse a customer.

Address-based limits misfire where many people share one address, which is normal on mobile networks and in offices. Challenges break the automation you asked for: monitoring, payment callbacks, and integrations. Rules written during an incident stay in place afterwards and quietly remove traffic nobody is watching.

The rule that holds: measures should expire on their own, and where a decision is uncertain, slowing a client is safer than refusing it. A delay annoys a customer; a block loses one.

Where the platform sits

This is the layer Bridge WAF exists for. Requests are inspected before reaching your origin, rate limiting is applied per domain, and abusive patterns are handled without writing a rule for each variation. Requests that never arrive cost your servers nothing. What this does not address is traffic that saturates a link, which belongs to a different layer entirely. See what the platform offers at Bridge CDN.

Questions

What is an HTTP flood?

An attack that sends large numbers of ordinary, valid requests in order to exhaust the application rather than the network. It is the most direct member of this family: no cleverness in any individual request, simply more of them than the backend can complete.

Does a WAF stop HTTP floods?

This is the layer where it applies, since complete requests exist to count and to limit. The defence is quantitative rather than qualitative: it restricts how much any one client may consume, because no rule can identify a request that is wrong in itself.

Why can I not just block the bad requests?

Because there are no bad requests to block. Each one is well formed and plausible, and the only distinguishing information lives across many of them: how fast they arrive, from how many places, and what they cost you to answer.

Is a repeated User-Agent proof of an attack?

No, on two separate grounds. The header is chosen by whoever sends the request and can say anything at all, and large populations of genuine browsers legitimately share identical strings, so a match is evidence of neither the sender's identity nor their intent.

Are POST floods worse than GET floods?

Usually, because submissions force parsing and writing, and writes are the operations hardest to serve from a cache or spread across more machines. A request that reads can be absorbed by capacity; a request that writes has to be handled where the data lives.

What should I limit first?

The endpoints that cost the most to answer, with a tighter allowance than the rest of the site. Search, report generation, and anything that writes deserve their own limits, because a uniform limit across the site is set either too loosely for those or too tightly for everything else.

Where the platform sits

The layer this product exists for: complete requests exist to count, so the defence is quantitative rather than qualitative.

off

No request is inspected and no allowance is counted.

monitor

What a limit would have refused is recorded while every request is still served.

block

Requests past the allowance are refused at the edge, and still recorded.

The firewall layer is included with Bridge CDN. Start in monitor: nothing is refused until you decide it should be.

Get started