Attack Anatomy
Why Rate Limiting Alone Can't Stop Modern DDoS Attacks
Christopher Plunk
Chief Technology Officer
CThere is a kind of DDoS that goes straight through SYN cookies, SYNPROXY, and every rate
limit you have set, and it does that while looking exactly like your real customers. If
your plan for an attack is a large enough rate limit, this is the one that takes you down
anyway.
We deal with it in production. This post covers what it is, why rate limiting can't fix
it no matter how you tune it, and the approach that does.
Two floods that a defender sees completely differently
Most DDoS defenses were built for one kind of flood. The trouble is there are two, and
they break on opposite sides.
The spoofed volumetric flood
The classic SYN flood forges its source addresses. It sends millions of connection
requests from IPs it does not own, and it never plans to finish the conversation.
This one is handled. The defense is stateless challenge and response:
-
SYN cookies encode the connection state inside the sequence number, so the server holds
no half-open state. A spoofed source never gets the reply, so it never finishes the
handshake and is dropped for free. -
SYNPROXY does the same job at the edge, in the kernel, before the packet reaches your
application.A forged source cannot answer the challenge, because the answer goes to the address it
faked. Every serious provider handles this. If a vendor's pitch ends here, they are
solving a problem from 2010.
The non-spoofed distributed flood
Now the attacker uses a real botnet: thousands, sometimes hundreds of thousands, of
compromised machines, each with a real IP and a working network stack.
Every bot opens a real TCP connection. It finishes the three-way handshake. It speaks
valid protocol. Then it holds the slot, or it tears down and reconnects from a fresh
address, again and again.
Here is the problem. At layer 4 this looks the same as a cold legitimate connection. A
first-time customer reaching your game server, your API, or your SSH bastion produces the
same wire signature: a real SYN, a real handshake, valid data. SYN cookies pass it,
because the handshake is real. SYNPROXY passes it for the same reason. A challenge-based
defense has nothing to challenge.
So you reach for a rate limit, and the numbers stop working in your favor.
The math of a shared rate limit
Protect a service with a rate limit of any kind: a token bucket, a connections-per-second
cap, whatever you like. Legitimate traffic and attack traffic pull from the same budget,
because you cannot tell them apart. That was the whole problem.
If your cap admits C connections per second, legitimate demand is L, and the flood is F,
your real users get this share of the admits:
legit admitted = C x L / (L + F)
Put real numbers in. Say L is 200 real users and F is 60,000 attacking connections per
second. Your legitimate users get about 0.3 percent of the budget. The rest goes to the
flood. Customers see timeouts and failed connections. The service is down in every way
that matters.
The obvious fix is to raise the cap. It does not help. A bigger C admits more flood in
the same proportion as more legit traffic, so the ratio L / (L + F) does not move. All
you have done is deliver more of the attack to the origin you were trying to protect. At
any finite cap a shared bucket hands the minority, your real users, a share of
L / (L + F), and a large enough flood drives that toward zero. No value of the limit
fixes it. The starvation is structural, not a tuning problem.
This is what goes wrong during an incident. The team watches legit users get starved,
cranks every limit up, and only ships more attack traffic to the thing under attack.
What actually works: telling them apart
If you cannot out-tune a shared bucket, the only way out is to stop sharing it between
attacker and customer. That means separating them, and since they are identical for one
packet, you have to judge them over time and by behavior rather than on any single packet.
The approach that holds up against this class comes down to one shift: judge a source by
how it behaves over time, not by any single packet.
-
Behavioral admission. A real client and a flood bot are identical for one packet, but
they diverge across a full exchange. We make a source earn its slot by behaving the way a
genuine client does, which thins the flood out before it ever competes with real users for
capacity. The survivors are no longer up against the full attack. -
Earned trust for proven-good sources. Once a connection is genuinely in use, it
produces signals a flood cannot cheaply reproduce. We use those to fast-track sources that
have already proven themselves, so returning legitimate users are not stuck behind the gate
on every connect. -
Reputation that only subtracts. Sources that clearly misbehave get pulled out of the
shared budget. We only ever act on proof a source generates about itself, never on how much
traffic it sends, so an attacker cannot fake the signal to get your real users blocked.Two things are not on that list: a bigger rate limit and a cleverer signature. A signature
that blocks packets matching some pattern fails the moment the attacker changes the pattern,
and against a non-spoofed flood there is nothing malformed to match on to begin with. The
durable answer is behavioral, and it has to run somewhere it can act on millions of packets
per second without falling over.
Where the filtering runs decides whether it works
All of this is pointless if the filtering sits too deep in the stack. By the time a flood
reaches your application, or even your host TCP stack, you have already paid for it in
CPU, memory, and connection-table pressure.
Sterile filters at the NIC driver layer with XDP and eBPF, before the packet reaches the
kernel TCP stack. Clean traffic is tunneled to your origin. Attack traffic is dropped in
the driver, at line rate, on commodity hardware. Everything described above runs right
there, at the edge, before your infrastructure ever sees the flood. Your origin only ever
meets traffic that already earned its way through.
What this means for you
Game server operators (FiveM, Minecraft, Rust). You are the main target for this exact
attack. Non-spoofed floods from booter and stresser botnets complete handshakes and bury
real players. A provider whose story ends at "we have SYN cookies" will not save your
server. Ask how they handle non-spoofed, handshake-completing floods, specifically.
Hosting providers and ISPs. You are selling uptime. The math above is what turns "we
rate limit at the edge" into a wall of support tickets during an incident. Behavioral
admission at the edge is what keeps your customers' cold connections alive while the attack
runs.
Enterprise and SaaS. Your SLA depends on cold-connection success under load: the new
customer, the failover, the health check. That is exactly what a shared rate limit starves
first. The number that matters is not how much you dropped, it is whether first-time
connections still got through.
Frequently asked questions
Is a big enough rate limit eventually enough?
No. A bigger cap admits more attack in the same proportion as legit traffic. The share your
users get is set by the ratio of legit to attack volume, not by the cap, and a larger flood
drives it toward zero.
Do SYN cookies stop this?
They stop spoofed floods, where the source cannot complete the handshake. A non-spoofed
distributed flood completes a real handshake, so SYN cookies and SYNPROXY pass it. There is
nothing for them to challenge.
Can you just block the attacking IPs?
There are often hundreds of thousands of them, spread about one or two per /24 subnet, so
prefix-level blocking either misses them or catches real users in the same subnets. The set
also rotates constantly. Static blocklists lose that race.
So what stops it?
Behavioral discrimination at the edge: making a source prove it behaves like a real client
before it earns a slot, fast-tracking sources that have already proven themselves, and
removing the ones that clearly misbehave, all in the NIC driver before the flood reaches your
origin.
This is the class of attack Sterile is built to stop. See how it
works or get in touch.
Stay online. Stay Sterile.