WAF & Edge Security
The outer wall: filtering malicious traffic at the edge before it ever reaches your servers.
What a Web Application Firewall is
A Web Application Firewall (WAF) is a filter that sits in front of your application and inspects every incoming HTTP request for malicious content. Where an ordinary network firewall decides whether to allow traffic based on addresses and ports (the plumbing), a WAF reads the actual request — the URL, headers, cookies, and body — and asks a different question: does this request look like an attack?
One recap you need and nothing more. Network people talk about layers: "L3/L4" means the low-level plumbing (IP addresses and TCP/UDP ports — the envelope), and "L7" means the application content itself (the HTTP request — the letter inside). A WAF is an L7 device: it understands HTTP, so it can catch attacks that hide inside a perfectly well-formed connection.
A WAF does not replace secure code — a well-written application should reject bad input on its own. It is a second wall: it blocks known attack shapes early, buys time to patch, and stops broad automated scanning from ever reaching your logic.
┌──────────────────────────────────────────────┐
│ Ordinary firewall (L3/L4) │
│ "Is this IP/port allowed?" ── envelope │
├──────────────────────────────────────────────┤
│ WAF (L7) │
│ "Does this HTTP request look malicious?" │
│ reads URL + headers + cookies + body │
└──────────────────────────────────────────────┘The OWASP Top 10 it targets
The OWASP Top 10 is a widely used, community-maintained list of the most common and dangerous web application weaknesses (OWASP is the Open Worldwide Application Security Project, a nonprofit that publishes free security guidance). A WAF is one of the tools that helps blunt several of these. It is worth naming the concrete attacks a WAF looks for, because its rules are essentially pattern-matchers for exactly these shapes.
| Attack | What the attacker does | What it looks like in a request |
|---|---|---|
| SQL injection (SQLi) | Smuggles database commands into an input so the database runs them | id=1' OR '1'='1 in a query string |
| Cross-site scripting (XSS) | Injects a script that runs in another user's browser | <script>steal()</script> in a comment field |
| Path traversal | Walks out of the intended folder to read arbitrary files | ../../etc/passwd in a filename parameter |
| Command injection | Sneaks shell commands into an input passed to the operating system | ; rm -rf / appended to a value |
| Remote file / template injection | Tricks the app into fetching or evaluating attacker content | Odd {{...}} or remote URLs where a plain value belongs |
The unifying idea: each of these is an input that looks like data but is crafted to be interpreted as code or a command. A WAF recognizes the tell-tale syntax of these payloads and rejects the request before your application ever parses it.
Negative and positive rule models
A WAF decides what to block using rules, and there are two opposite philosophies for writing them. Knowing which model you are running explains most of a WAF's day-to-day behavior.
- Negative model (signature / blocklist). Allow everything except requests matching a list of known-bad patterns. This is the common default: it recognizes the syntax of SQLi, XSS, and the rest. The widely used starting rule set here is the OWASP Core Rule Set (CRS) — a free, maintained bundle of attack signatures. Strength: works out of the box against known attacks. Weakness: it can only catch what it has a signature for, and it can misfire on legitimate-but-weird input.
- Positive model (allow-list). Block everything except requests that match a description of what valid traffic looks like — this endpoint accepts only these fields, of these types, within these lengths. Strength: it blocks novel attacks it has never seen, because anything unexpected is denied by default. Weakness: it is far more work to build and must be updated every time the application changes.
Real deployments blend the two: start with the negative CRS for broad coverage, then tighten high-value endpoints (login, payments) with positive allow-list rules.
Negative model Positive model
────────────── ──────────────
default = ALLOW default = DENY
block if matches allow if matches
known-bad signature known-good shape
│ │
fast to deploy hard to build
misses novel attacks catches novel attacksManaged versus self-hosted
You can run a WAF yourself or rent one, and the choice is the familiar build-versus-buy trade-off applied to security.
| Self-hosted | Managed | |
|---|---|---|
| Examples | ModSecurity (an open-source WAF engine that runs inside your web server, paired with the OWASP CRS) | Cloudflare WAF, AWS WAF, Akamai — run at the provider's edge |
| Control | Full — you own every rule | Limited to what the provider exposes |
| Operational load | You patch, tune, and scale it | The provider does |
| Rule updates | You pull new signatures | Updated for you, often within hours of a new threat |
| Where it runs | On or beside your servers | At a global edge network, far from your origin |
The practical pull toward managed WAFs is that new attack signatures and, crucially, volumetric-attack absorption (next section) arrive without you doing anything. Self-hosting makes sense when you need total control, have strict data-locality rules, or want to avoid a third party seeing your traffic.
Rate limiting, bot mitigation, and geo-blocking
Beyond payload inspection, an edge WAF enforces coarser policies about who and how much. These are cheap to apply at the edge and stop whole categories of abuse.
- Rate limiting. Cap how many requests a single client (by IP, API key, or user) may make in a window — say 100 requests per minute. It blunts brute-force login attempts, scraping, and accidental floods from a buggy client. The response for an exceeded limit is HTTP 429 Too Many Requests.
- Bot mitigation. Distinguish humans and well-behaved bots (search crawlers) from malicious automation (credential-stuffing scripts, scrapers). Signals include request rate, missing browser headers, and behavioral fingerprints; suspicious clients get a challenge (a proof-of-work or interactive check) instead of an outright block.
- Geo-blocking. Allow or deny by the country the request's IP maps to. Useful when a service is only offered in certain regions, or to shed traffic from regions that generate only abuse. It is a blunt tool — a determined attacker uses a proxy in an allowed country — so treat it as noise reduction, not a real boundary.
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json
{ "error": "rate_limit_exceeded", "limit": 100, "window": "60s" }
The theme: these controls do not inspect what a request says, only its pattern — frequency, origin, and how automated it looks. They are the fast, cheap first sieve before the more expensive payload inspection runs.
DDoS protection at the edge
A Denial-of-Service (DoS) attack tries to overwhelm a service so real users cannot reach it; a Distributed DoS (DDoS) does it from many machines at once, often a botnet of thousands. Defending against this is a headline reason to put a large edge network in front of your origin, because the defense is fundamentally about capacity. There are two flavors, and they are stopped in different ways.
| Volumetric (L3/L4) | Application-layer (L7) | |
|---|---|---|
| Goal | Saturate the network pipe with sheer traffic | Exhaust the app with expensive-looking requests |
| Example | A flood of UDP or SYN packets, gigabits per second | A flood of requests to a costly search endpoint |
| What stops it | Absorb and filter at a huge distributed edge with more capacity than the attack | Rate limiting, bot challenges, and behavioral analysis |
| Tell | Enormous packet counts, little valid HTTP | Requests look almost legitimate, one at a time |
The edge advantage is arithmetic: a global network with terabits of capacity can soak up a volumetric flood that would instantly crush a single data center. L7 attacks are subtler — each request looks reasonable — so they are caught by the rate-limiting and bot-mitigation logic from the previous section rather than by raw capacity. A serious edge platform does both: it dilutes the flood and then filters what remains.
L3/L4 volumetric flood L7 request flood
────────────────────── ────────────────
millions of packets/s many "valid" requests
→ absorbed by edge capacity → caught by rate limit
(bigger pipe wins) + bot challengeTLS termination at the edge
TLS (Transport Layer Security) is the encryption behind HTTPS: it scrambles traffic between the browser and the server so no one in between can read or tamper with it. TLS termination means the edge is where that encryption is decrypted — the edge holds the certificate, decrypts the request, and only then can a WAF read the plaintext HTTP to inspect it.
This is a quiet but important point: a WAF cannot inspect encrypted bytes. It must see the decrypted request to look for a SQLi payload. So the edge decrypts (terminates TLS), the WAF inspects the plaintext, and the edge then re-encrypts for the final hop to your origin — or forwards over a trusted internal link. The upside is one central place to manage certificates and inspect traffic; the responsibility is that this edge now sees your users' plaintext, so it must be trusted and locked down.
Browser ──TLS──► Edge ──inspect──► Origin
encrypted │ re-encrypted
│
decrypt here so
the WAF can read
the real requestPutting the edge together
All of the above lives in one place — the edge, the layer of servers between the public internet and your origin. It is worth seeing the whole path a request travels, because each stage drops a different kind of bad traffic so your origin only ever sees what survived every filter.
A CDN (Content Delivery Network) is the cache in that stack: it stores copies of your static content (images, scripts, pages) at the edge and serves them directly, so most traffic never touches your origin at all. Bundling WAF, DDoS defense, TLS, and CDN into one edge is common precisely because they share the same position in the path and reinforce each other — the CDN reduces load, and the freed capacity helps absorb attacks.
Client
│ HTTPS
▼
┌──────────────────────── EDGE ────────────────────────┐
│ DDoS absorption → soak up volumetric floods │
│ TLS termination → decrypt so the WAF can inspect │
│ WAF (L7) → block SQLi / XSS / bad payloads │
│ Rate limit + bots → shed floods and automation │
│ CDN cache → serve static content, spare origin│
└───────────────────────────────────────────────────────┘
│ only clean, allowed traffic
▼
Origin serversFalse positives and tuning
A false positive is when the WAF blocks a legitimate request because it looks like an attack — a user writes a comment containing SELECT * FROM while discussing databases, and a SQLi signature fires. This is the central operational reality of running a WAF: too loose and attacks slip through; too strict and you block real customers.
The disciplined way to introduce a WAF avoids both extremes:
- Start in monitor mode. Run the rules in "log but do not block" mode first. You collect what would have been blocked without breaking anyone, and you learn your traffic's real shape before enforcing.
- Tune from real logs. Review what fired. Genuine attacks stay blocked; legitimate patterns that tripped a rule become tuned exceptions (allow this parameter to contain angle brackets on this one endpoint).
- Then enforce, and keep watching. Switch to blocking, but keep reviewing, because your application and its traffic keep changing.
The mindset: a WAF is not a set-and-forget appliance. It is a living policy that trails your application. An untuned WAF either annoys users with false blocks until someone disables it in frustration — the worst outcome, since now there is no wall at all — or is left so permissive it stops nothing. Tuning is what keeps it both trusted and effective.
Key takeaways
- A WAF is an L7 filter: it reads the actual HTTP request (URL, headers, body) and blocks requests that look like attacks — a second wall in front of, not a replacement for, secure code.
- It targets the OWASP Top 10 shapes — SQLi, XSS, path traversal, command injection — each of which is input crafted to be interpreted as code rather than data.
- Rules follow a negative model (block known-bad signatures, e.g. the OWASP CRS) or a positive model (allow only known-good shapes); real deployments blend both.
- Managed WAFs (Cloudflare, AWS WAF) trade control for automatic updates and edge-scale DDoS absorption; self-hosted (ModSecurity) gives full control at higher operational cost.
- The edge also does rate limiting, bot mitigation, and geo-blocking — policies about who and how much, not what — plus DDoS defense: volumetric L3/L4 floods are absorbed by capacity, L7 floods are caught by rate limits and challenges.
- TLS must terminate at the edge so the WAF can inspect plaintext; that makes the edge a trusted, sensitive component.
- Every WAF fights false positives; start in monitor mode, tune from real logs, then enforce — it is a living policy, never set-and-forget.
Checklist
- [ ] I can explain how a WAF (L7) differs from an ordinary network firewall (L3/L4).
- [ ] I can name concrete OWASP Top 10 attacks and describe how each hides code inside data.
- [ ] I can contrast the negative (signature/CRS) and positive (allow-list) rule models.
- [ ] I can weigh managed versus self-hosted (ModSecurity) WAFs.
- [ ] I can explain rate limiting (429), bot mitigation, and geo-blocking as who/how-much controls.
- [ ] I can distinguish volumetric (L3/L4) from application-layer (L7) DDoS and how each is stopped.
- [ ] I can explain why TLS terminates at the edge before a WAF can inspect a request.
- [ ] I can describe the monitor-mode-then-tune process for handling false positives.