DDoS Protection and Abuse Prevention
When the attack isn’t stealing data but drowning you in traffic. You can’t out-provision a botnet —
so the game is filtering, absorbing, and making abuse expensive.
Prerequisites: Rate Limiting, CDN
Time to read: ~18 minutes
The problem
A Denial of Service attack tries to make your system unavailable — not by breaking in, but by
exhausting a resource: bandwidth, connections, CPU, memory, or a downstream dependency.
A Distributed Denial of Service (DDoS) does it from thousands or millions of sources (a botnet),
so you can’t just block one IP.
🚨 The asymmetry is the whole problem: attacks are cheap, defence is expensive. An attacker rents a
botnet for a few hundred dollars and generates terabits of traffic. You cannot buy enough servers to
absorb it — and even if you could, you’d be paying to serve attack traffic. The defence is not
“more capacity” but filtering the attack out before it reaches you.
The three layers of attack
DDoS attacks target different layers, and they need different defences.
Volumetric (L3/L4) — flood the pipe
Overwhelm your bandwidth with sheer volume — UDP floods, ICMP floods, and especially
amplification attacks.
🚨 Amplification is how small attacks become huge: the attacker sends a small request to a
misconfigured third-party server (DNS, NTP, memcached) with your IP spoofed as the source. The server
sends a large response to you. A 60-byte request can trigger a 4,000-byte response — a 70× (or
with memcached, 50,000×) amplification. The attacker’s bandwidth is multiplied against you.
Defence: you cannot absorb this yourself. You need a network with more capacity than the
attack — a scrubbing service or CDN that soaks up terabits and forwards only clean traffic.
Protocol (L3/L4) — exhaust connection state
Exhaust server resources with malformed or half-open connections. The classic is a SYN flood: send
TCP SYN packets, never complete the handshake, and fill the server’s connection table with half-open
connections until it can’t accept real ones. → TCP
Defence: SYN cookies (the server doesn’t allocate state until the handshake completes), connection
rate limiting, and stateful firewalls — mostly handled by your infrastructure or CDN.
Application (L7) — expensive requests
🚨 The hardest to defend and increasingly common. Instead of raw volume, send legitimate-looking
requests that are individually expensive — a costly search query, a report generation, a login (which
triggers password hashing), or a GraphQL query with deep nesting. A few thousand of these can exhaust
your CPU or database while looking like normal traffic.
Why it’s hard: the requests are valid HTTP, from real-looking clients, so simple volume-based
filtering doesn’t catch them. You have to distinguish abuse from legitimate use at the application
level.
Defence: rate limiting, CAPTCHA, behavioural
analysis, query cost limits, and caching so repeated expensive requests are cheap.
The layered defence
No single control stops DDoS. You layer them, filtering as early and cheaply as possible.
flowchart TB
A[Attack traffic] --> CDN[CDN / Anycast edge<br/>absorb volumetric, spread load]
CDN --> S[Scrubbing / WAF<br/>filter malicious patterns]
S --> RL[Rate limiting<br/>per-IP, per-user, global]
RL --> LS[Load shedding<br/>drop low-priority under pressure]
LS --> APP[Your application]
🚨 The principle: reject as early and as cheaply as possible. A request blocked at the CDN edge
costs you nothing; one that reaches your database has already consumed CPU, a connection, and a query.
Each layer removes more, so less reaches the expensive layers.
1. Anycast + CDN (the foundation). A CDN with
anycast spreads attack traffic across hundreds of global PoPs, so no
single location is overwhelmed, and its enormous aggregate capacity absorbs volumetric floods. 🚨
This is the single most important DDoS defence — the CDN’s capacity dwarfs any botnet, and it’s
distributed. Cloudflare, Akamai, AWS Shield, and Google Cloud Armor all provide this.
2. WAF (Web Application Firewall). Filters malicious request patterns — known attack signatures,
SQL injection attempts, bad bots. Sits at the edge.
3. Rate limiting. Per-IP, per-user, per-endpoint, and global.
→ Rate Limiting
4. Load shedding. Under overload, drop low-priority traffic to keep serving the essential.
→ Resilience Patterns
🚨 Origin protection is critical: if attackers find your origin’s real IP, they bypass all of the
above. Lock the origin firewall to accept traffic only from the CDN’s IP ranges, and don’t leak the
origin IP (via DNS history, an unproxied subdomain like mail., or certificate transparency logs).
→ CDN
Abuse prevention (the broader problem)
DDoS is the loud version. There’s a quieter category of abuse that also needs designing against —
attackers using your system as intended but at scale or for the wrong purpose:
Credential stuffing / brute force — trying stolen username/password pairs at scale. Defences:
rate limiting per account and per IP, MFA, breached-password checks, CAPTCHA
after failures, and 🚨 not revealing whether a username exists.
Scraping — bulk-extracting your data. Defences: rate limiting, bot detection, CAPTCHA,
cursor-pagination limits, and legal terms.
Spam / content abuse — fake accounts, spam posts. Defences: email/phone verification, rate
limits on creation, content filtering, reputation systems.
Resource abuse / denial of wallet — 🚨 an increasingly important one in the cloud/serverless era:
triggering your costs. Attackers hammer a serverless function or a metered API to run up your bill
(you scale up and pay, rather than falling over). Defences: hard concurrency/spend limits, budget
alarms, and rate limiting. → Serverless
Fraud — abusing business logic (fake orders, coupon abuse, fake reviews). A whole domain of its
own. → Fraud Detection
The economics: make abuse expensive
🚨 The strategic frame worth internalizing: you can rarely make attacks impossible, so make them
uneconomical. Every defence raises the attacker’s cost or lowers their return:
- CAPTCHA / proof-of-work — makes each request cost the attacker time or compute.
- Rate limiting — caps the return on a given IP/account, forcing more resources.
- MFA — makes stolen passwords nearly worthless, killing credential stuffing’s economics.
- Cost/spend limits — caps your loss from denial-of-wallet.
- Behavioural detection — makes evasion require sophistication.
The goal is to shift the attacker toward an easier target. Perfect security is impossible; making
yourself more expensive to attack than the next target is achievable.
Detection and response
🚨 You can’t defend what you don’t see. DDoS response depends on detection:
- Baseline your normal traffic — so an anomaly (a 50× spike, traffic from unusual geographies, a
surge on one endpoint) stands out. → Monitoring
- Automated mitigation — modern DDoS protection (Cloudflare, AWS Shield Advanced) detects and
mitigates in seconds, faster than a human. Manual response is too slow for a fast attack.
- A runbook — who does what during an attack, how to enable stricter modes (“I’m under attack”
mode), how to communicate.
- Graceful degradation — under attack, shed non-essential features to keep the core alive rather
than failing entirely. → Resilience
⚖️ Trade-offs
| Defence |
Protects against |
Cost |
| CDN / anycast |
Volumetric floods |
Money; another layer; origin must be hidden |
| WAF |
Known attack patterns |
False positives blocking real users |
| Rate limiting |
Brute force, scraping, L7 floods |
Legitimate heavy users hit limits |
| CAPTCHA |
Bots, automation |
Real-user friction; accessibility issues |
| Load shedding |
Overload |
Some legitimate requests dropped |
| Cost limits |
Denial of wallet |
May cap legitimate spikes |
🚨 Every defence has a false-positive cost — blocking real users. Aggressive DDoS protection during
an attack (challenge every request) protects availability but degrades the experience for everyone,
including legitimate users. It’s a deliberate trade you make during an attack, not by default.
In the real world
- The 2016 Dyn attack used the Mirai botnet (compromised IoT devices) to DDoS a major DNS
provider, taking down Twitter, Reddit, Spotify, and GitHub — while their own servers were healthy.
It showed that DNS is a target and that IoT botnets can generate massive traffic.
→ DNS
- The largest recorded attacks exceed tens of terabits per second and hundreds of millions of
requests per second — volumes no individual origin can absorb, which is why CDN/scrubbing services
(whose networks have hundreds of Tbps of capacity) are the only viable defence.
- Denial-of-wallet on serverless is a recognized emerging threat — a bug or attack that triggers
massive invocation counts turns into a massive bill, since serverless scales up and charges rather
than falling over. It’s why concurrency and budget limits are essential from day one.
🚨 Interview traps
- “We’ll add more servers.” You can’t out-provision a botnet, and you’d pay to serve attack
traffic. Filter, don’t absorb.
- Not mentioning a CDN/anycast layer. It’s the foundational volumetric defence.
- Leaving the origin publicly reachable while relying on a CDN for protection.
- Ignoring L7 (application-layer) attacks — expensive-request floods that look legitimate.
- No rate limiting on expensive or auth endpoints.
- Forgetting denial-of-wallet in serverless/metered designs.
- No detection/monitoring — you can’t respond to what you can’t see.
- Not acknowledging the false-positive trade-off of aggressive defence.
🎙️ Soundbites
- “You can’t out-provision a botnet — the economics favour the attacker. So the defence is filtering,
not absorbing: a CDN with anycast spreads and soaks up volumetric traffic across hundreds of PoPs
whose aggregate capacity dwarfs any attack, and forwards only clean traffic.”
- “I’d reject as early and cheaply as possible — CDN edge, then WAF, then rate limiting, then load
shedding. A request blocked at the edge costs nothing; one that reaches the database has already
cost us CPU and a connection.”
- “Application-layer attacks are the hard ones — expensive but legitimate-looking requests. Rate
limiting by cost, caching, and query-cost limits, not just volume filtering.”
- “Critically, the origin has to be locked to the CDN’s IP ranges. If attackers find the real origin
IP, they bypass every defence — and origins leak through DNS history and certificate logs.”
- “For the serverless parts, denial-of-wallet is a real risk — I’d set hard concurrency and budget
limits, since the system scales up and bills us rather than failing.”
🛠️ Try it
1. Load-test your own service to failure. Use k6 or wrk to hammer an endpoint and find where it
falls over — and how. Does it run out of connections, CPU, memory, or database connections? That’s
your DDoS weak point, and knowing it is the first step to defending it.
2. Find an expensive endpoint. In your own app, identify the request that costs the most (a search,
a report, a login with hashing). Calculate how many per second would exhaust your resources. That’s
your L7 attack surface — usually far fewer requests than you’d expect.
3. Simulate rate limiting under attack. Add per-IP rate limiting, then attack from a few “IPs”
(spoofed in a header) and confirm they get throttled while a legitimate client still works. Then attack
from many IPs and watch per-IP limiting fail — demonstrating why you need global limits and CDN-level
defence too.
4. Check your origin exposure. For any site behind a CDN, try to find the real origin IP via DNS
history tools or certificate transparency logs (crt.sh). If you can find it, so can an attacker —
and they’d bypass the CDN.
Check yourself
1. Why can't you defend against a volumetric DDoS by adding capacity?
Because the economics are hopelessly asymmetric. An attacker can rent a botnet or use amplification to
generate terabits per second of traffic for a few hundred dollars, while provisioning enough
infrastructure to absorb that would cost you enormously — and you'd be paying to *serve attack
traffic* that produces no value. Even the largest single origins can't match the tens of terabits per
second of the biggest attacks. The only viable defence is *filtering the attack out before it reaches
you*, using a network whose aggregate capacity genuinely exceeds any attack — a CDN or scrubbing
service with hundreds of Tbps spread across hundreds of anycast locations, which absorbs the flood and
forwards only clean traffic. You defend by filtering, not by out-provisioning.
2. What is an amplification attack and why is it dangerous?
The attacker sends a small request to a misconfigured public server (DNS, NTP, memcached) but spoofs
the *source* IP to be the victim's. The server sends its (much larger) response to the victim, who
never asked. Because the response is many times bigger than the request — 70× for DNS, up to 50,000×
for memcached — the attacker multiplies their own bandwidth against the target: a modest attacker
connection generates a massive flood at the victim. It's dangerous because it lets a small attacker
produce enormous traffic, it uses innocent third-party servers as unwitting weapons (making it hard to
trace and block at source), and the spoofed source means the victim can't easily identify the real
attacker. It's a major component of the largest recorded DDoS attacks.
3. Why are application-layer (L7) DDoS attacks harder to defend than volumetric ones?
Because the traffic looks legitimate. A volumetric attack is obviously abnormal — a flood of malformed
packets or raw volume that a CDN can identify and drop by pattern. An L7 attack sends *valid* HTTP
requests from real-looking clients, but chooses requests that are individually expensive: a costly
search, a report generation, a login that triggers password hashing, a deeply-nested GraphQL query. A
few thousand of these exhaust your CPU or database while being indistinguishable, at the network
level, from genuine users doing normal things. So you can't filter them by volume or signature; you
have to distinguish abuse from legitimate use at the application level — via rate limiting by cost,
behavioural analysis, CAPTCHA, query-cost limits, and caching so repeated expensive requests become
cheap. It's the boundary between "block obvious garbage" and "is this a real user?", which is genuinely
hard.
4. Why must the origin be hidden when using a CDN for DDoS protection, and how does it leak?
Because the CDN can only protect traffic that flows through it. If an attacker discovers your origin
server's real IP address, they send the attack directly to the origin, completely bypassing the CDN's
filtering and absorption — so all your protection is worthless. The origin leaks through several
channels: DNS history services (which record the IP before you moved behind the CDN), unproxied
subdomains that still point directly at origin (`mail.example.com`, `ftp.`, `staging.`), certificate
transparency logs (which list every certificate issued for your domains), email headers (originating
IP), and misconfigured services that reveal it. Defences: firewall the origin to accept traffic *only*
from the CDN's published IP ranges (or use an authenticated private link), rotate the origin IP after
enabling the CDN, proxy *every* DNS record, and audit for leaks.
5. What is "denial of wallet" and why is it a concern for serverless architectures?
An attack (or bug) that inflicts cost rather than downtime by triggering your usage-based charges. In a
traditional fixed-capacity system, excess traffic causes degradation or an outage — bad, but bounded.
In a serverless or auto-scaling metered system, the platform *scales up to meet the load and bills you
for it*: an attacker hammering a Lambda function or a metered API doesn't take you down, they run up
your bill, potentially to five or six figures, because per-request billing has no natural ceiling. A
recursive trigger (a function writing to the bucket that invokes it) or a retry loop can do it
accidentally. Defences: hard concurrency limits per function, account-level spend/budget alarms with
automated response, rate limiting on public endpoints, and extreme care with any trigger whose output
could re-invoke it. It's a reason to set these limits from day one rather than after the first
surprise bill.
Further reading