How Web Application Firewalls Work: Layer 7 HTTP Security
A Web Application Firewall (WAF) is a security layer that inspects, filters, and blocks malicious HTTP/HTTPS traffic before it reaches a web application. Unlike traditional network firewalls that operate at Layers 3-4 (IP addresses and ports), a WAF operates at Layer 7 -- it understands HTTP semantics, parses request headers, bodies, cookies, and URL parameters, and applies rules that detect attack patterns like SQL injection, cross-site scripting (XSS), and cross-site request forgery (CSRF). WAFs sit in the request path between the client and the web server, acting as a reverse proxy that terminates the HTTP connection and re-originates it to the backend only if the request passes all security checks.
The need for WAFs arises from a fundamental asymmetry in web security: web applications are complex, frequently updated, and inevitably contain vulnerabilities. Even with rigorous secure development practices, the combination of legacy code, third-party dependencies, and rapid deployment cycles means that production applications routinely have exploitable flaws. A WAF provides a defense-in-depth layer that can block known attack patterns even when the underlying application is vulnerable. It is not a replacement for secure coding -- a WAF cannot fix the vulnerability -- but it buys time for developers to patch while preventing exploitation.
WAFs are deployed in three primary configurations: inline (reverse proxy), where the WAF sits directly in the request path and can block requests in real time; out-of-band (passive/monitoring), where the WAF receives a copy of traffic (via port mirroring or tap) and generates alerts without blocking; and embedded (agent/module), where WAF logic runs inside the web server itself (e.g., ModSecurity as an Apache/Nginx module). Cloud WAF services (Cloudflare WAF, AWS WAF, Akamai Kona) operate as inline reverse proxies at the CDN edge, inspecting requests before they reach the origin server.
Negative Security Model: Signature-Based Detection
The negative security model (also called "blocklist" or "deny-list") is the most common WAF approach. It works by maintaining a database of known attack patterns (signatures/rules) and blocking any request that matches. This is analogous to antivirus signature detection: the WAF knows what "bad" looks like and flags it.
A typical signature-based WAF rule might look like this (in ModSecurity rule language):
# Block SQL injection in query parameters
SecRule ARGS "@rx (?i)(\b(union|select|insert|update|delete|drop|alter)\b.*\b(from|into|set|table|where)\b)" \
"id:1001,phase:2,deny,status:403,msg:'SQL Injection Detected'"
# Block XSS in request body
SecRule REQUEST_BODY "@rx (?i)(<script[^>]*>|javascript\s*:|on(load|error|click|mouseover)\s*=)" \
"id:1002,phase:2,deny,status:403,msg:'XSS Detected'"
These rules use regular expressions to match patterns commonly found in attack payloads. The WAF evaluates each rule against the relevant parts of the request (URL path, query string, headers, cookies, POST body) and takes action (block, log, redirect, challenge) when a match occurs.
The OWASP Core Rule Set (CRS) is the most widely used open-source signature set, containing over 150 rules covering the OWASP Top 10 vulnerability categories. CRS uses a scoring system (anomaly scoring mode) where each rule match adds points to a request's anomaly score. If the total score exceeds a configurable threshold (typically 5 for paranoia level 1, lower for higher paranoia levels), the request is blocked. This scoring approach reduces false positives compared to blocking on any single rule match -- a legitimate request might trigger one low-severity rule (score +2) without reaching the blocking threshold, while an actual attack triggers multiple rules (score +15) and is clearly blocked.
Positive Security Model: Allowlists
The positive security model (also called "allowlist" or "whitelist") takes the opposite approach: instead of defining what is bad (and allowing everything else), it defines what is allowed and blocks everything that does not match. A positive security model WAF is configured with a strict schema for each endpoint: which HTTP methods are permitted, which parameters are expected, what data types and value ranges those parameters should have, and what content types are accepted.
For example, a positive security model rule for a login endpoint might specify:
Endpoint: POST /api/login
Content-Type: application/json
Parameters:
- username: string, length 3-64, pattern [a-zA-Z0-9._-]+
- password: string, length 8-128, any characters
- remember_me: boolean (optional)
No other parameters allowed.
No query string allowed.
Any request to /api/login that includes unexpected parameters, uses an unexpected HTTP method, or has parameter values outside the defined constraints is blocked. This approach is inherently more secure than signature-based detection because it blocks unknown attacks (zero-days) -- any input that does not conform to the schema is rejected, regardless of whether it matches a known attack pattern.
The downside is operational cost: creating and maintaining a positive security model requires detailed knowledge of every endpoint in the application. Every API change, new parameter, or endpoint addition requires WAF policy updates. This tight coupling between application and WAF configuration makes positive security models practical primarily for stable, well-documented APIs (especially REST APIs with OpenAPI/Swagger specifications) and impractical for large, rapidly evolving web applications.
Most production WAF deployments use a hybrid approach: a positive security model for critical endpoints (login, payment, admin) combined with a negative security model (CRS rules) as a catch-all for the rest of the application.
OWASP Core Rule Set (CRS) Deep Dive
The OWASP CRS is organized into rule groups that target specific attack categories:
- SQL Injection (SQLi): rules detect SQL keywords and syntax patterns in request parameters --
UNION SELECT,OR 1=1, comment sequences (--,/*), string concatenation operators, and database-specific functions (SLEEP(),BENCHMARK(),pg_sleep()). The rules account for various evasion techniques: case variations, URL encoding, Unicode encoding, comment insertion (UN/**/ION SEL/**/ECT), and string splitting. See how SQL injection works for detailed attack vectors. - Cross-Site Scripting (XSS): rules match HTML tags, event handlers, JavaScript URLs, and encoding variations used in XSS attacks. This includes
<script>tags,onerror/onloadattributes,javascript:URIs, data URIs with HTML content, and SVG-based XSS vectors. Content Security Policy provides complementary browser-side XSS protection. - Remote Code Execution (RCE): rules detect OS command injection patterns (
; cat /etc/passwd,| whoami, backtick execution), PHP code injection (<?php,eval(), and common webshell signatures. - Local/Remote File Inclusion (LFI/RFI): rules detect path traversal sequences (
../../etc/passwd), null bytes used to truncate file paths, and remote URL inclusion patterns (http://evil.com/shell.php). - Scanner/Bot Detection: rules identify automated scanning tools by their user-agent strings, request patterns, and timing characteristics. Requests from known vulnerability scanners (Nikto, sqlmap, Acunetix, Burp Suite) receive elevated anomaly scores.
- Protocol Enforcement: rules that enforce HTTP protocol compliance -- valid Content-Type headers, proper encoding, reasonable header sizes, and rejection of malformed requests that might exploit parser differentials between the WAF and the backend application.
CRS operates at four paranoia levels:
- PL1 (default): basic rules with minimal false positives. Suitable for most applications without tuning.
- PL2: adds rules that detect more evasion techniques but may trigger on some legitimate requests (e.g., requests containing SQL-like English words).
- PL3: aggressive detection that catches sophisticated evasion but requires significant tuning to avoid blocking legitimate traffic.
- PL4: maximum paranoia. Blocks almost everything that is not explicitly allowed. Requires extensive allowlisting for any real application to function.
WAF Bypass Techniques
WAF bypasses are a rich area of security research. Attackers exploit the semantic gap between how the WAF parses a request and how the backend application processes it. Common bypass categories:
Encoding Evasion
WAFs typically decode URL-encoding and Unicode before applying rules, but double encoding, mixed encoding, and charset-specific encoding can slip through:
# Standard SQL injection (blocked by WAF)
GET /search?q=' UNION SELECT password FROM users--
# Double URL encoding (may bypass)
GET /search?q=%2527%2520UNION%2520SELECT%2520password%2520FROM%2520users--
# Unicode normalization bypass
GET /search?q=%EF%BC%87%20UNION%20SELECT%20... (fullwidth apostrophe)
# Overlong UTF-8 encoding
GET /search?q=%C0%A7%20UNION%20SELECT%20... (overlong encoding of ')
The defense is to apply all decodings recursively (decode until no further decoding changes the string) and to normalize Unicode to NFC form before rule evaluation. CRS does this in its request normalization phase.
HTTP Parameter Pollution (HPP)
Different web frameworks handle duplicate parameters differently. If a WAF sees ?id=1&id=' OR 1=1, it might check only the first value (1, which is clean). But if the backend application uses the last value (as PHP does with $_GET['id']), the SQLi payload reaches the application unchecked. HPP can also split a payload across multiple parameters that the application concatenates.
HTTP Request Smuggling
When a WAF and the backend server disagree on where one HTTP request ends and the next begins, an attacker can "smuggle" a malicious request past the WAF. HTTP request smuggling exploits differences in how the WAF and backend interpret Content-Length and Transfer-Encoding headers. The WAF sees one benign request; the backend sees two requests, the second of which contains the attack payload.
Payload Fragmentation
Splitting an attack payload across multiple request elements that the WAF evaluates independently but the application concatenates:
# Payload split across cookie and parameter
Cookie: data='; DROP TABLE
GET /api?query= users;--
# Application code: query = cookie.data + request.query
# Reconstructed: '; DROP TABLE users;--
JSON/XML/Multipart Evasion
WAF rules often focus on URL-encoded form data. Attacks embedded in JSON bodies, XML documents (especially with CDATA sections or entity expansion), or multipart/form-data boundaries may evade rules that do not parse these content types deeply. Modern WAFs must parse all common content types, including GraphQL queries, protobuf payloads, and gRPC messages.
Case and Syntax Variations
SQL syntax allows many variations that can bypass simple pattern matching:
# Case variations
uNiOn SeLeCt
UnIoN/**/sElEcT
# Whitespace alternatives
UNION%09SELECT (tab)
UNION%0ASELECT (newline)
UNION/**_**/SELECT
# String concatenation (MySQL)
'UN' 'ION' ' SE' 'LECT'
CONCAT('UN','ION',' SE','LECT')
# Alternative syntax
1 AND 1=1 -> 1 && 1=1
1 OR 1=1 -> 1 || 1=1
WAF Performance and Latency
WAFs add latency to every request, and the performance cost depends on the complexity of the rule set and the size of the request body. Key performance considerations:
- Regular expression cost: complex regex patterns with nested quantifiers or alternations can cause catastrophic backtracking on crafted inputs (ReDoS). WAF regex engines should use Thompson NFA-based implementations (like RE2) rather than backtracking engines. OWASP CRS rules are designed to avoid ReDoS-vulnerable patterns, but custom rules must be tested carefully.
- Request body inspection: inspecting large POST bodies (file uploads, JSON payloads) consumes CPU and memory. Most WAFs limit body inspection to a configurable size (e.g., 128 KB for ModSecurity's
SecRequestBodyLimit). Requests with bodies larger than this limit are either passed without inspection (creating a bypass) or blocked entirely. - Rule count: each rule evaluation adds microseconds. A full CRS evaluation with 150+ rules at PL2 typically adds 1-5 milliseconds of latency per request. At PL4 with custom rules, this can reach 10-20 milliseconds. For high-traffic sites processing 100,000 requests per second, this translates to significant CPU utilization on the WAF infrastructure.
- TLS termination: inline WAFs must terminate TLS to inspect encrypted traffic. TLS handshake overhead (especially without session resumption) adds to the per-request cost. Cloud WAFs at CDN edge locations amortize this across their global infrastructure.
Rate Limiting Integration
WAFs often integrate with rate limiting to provide layered protection. While WAF rules detect malicious payloads in individual requests, rate limiting detects abusive request patterns: brute-force login attempts, credential stuffing, API abuse, and application-layer DDoS. The combination is powerful: rate limiting handles volume-based attacks that do not have distinctive payloads, while WAF rules handle attacks that use normal request volumes but malicious content.
Cloud WAF providers typically offer integrated rate limiting, bot management, and reputation-based blocking alongside their signature-based WAF rules. This holistic approach recognizes that modern attacks often combine multiple techniques -- a sophisticated attacker might use a botnet (bypassing rate limits per-IP) with obfuscated payloads (bypassing WAF signatures) delivered through residential proxy networks (bypassing IP reputation lists).
False Positives: The WAF Operator's Curse
The biggest operational challenge with WAFs is false positives -- blocking legitimate requests that happen to match attack patterns. Common false positive scenarios:
- Technical content: a blog post about SQL injection that includes example payloads. A forum post discussing JavaScript that contains
<script>tags in code blocks. A code paste service that receives actual code as input. - International text: Unicode characters that, after normalization, resemble SQL syntax or HTML special characters. CJK characters, Arabic text, and certain diacritical marks can trigger false positives in rules that are not properly Unicode-aware.
- Rich text editors: WYSIWYG editors that submit HTML markup in form fields. The WAF sees HTML tags and may flag them as XSS, even though the application intentionally accepts HTML input (with server-side sanitization).
- API payloads: JSON bodies containing SQL-like strings, XML with CDATA sections, or GraphQL queries with nested fragments. APIs that accept complex structured data are particularly prone to false positives.
- Long URLs and headers: some WAFs have default limits on URL length, header count, or cookie size that trigger on legitimate requests from applications that use long JWT tokens in cookies or complex query strings.
Tuning a WAF to minimize false positives while maintaining security is an ongoing process. Best practices include:
- Deploy in detection mode (log-only) before switching to blocking mode. Analyze the logs for false positives and add exclusions.
- Use targeted rule exclusions rather than disabling entire rule groups. For example, exclude the SQLi rules for a specific parameter on a specific endpoint rather than disabling all SQLi detection.
- Start at CRS PL1 and increase the paranoia level only after tuning at the current level produces acceptable false positive rates.
- Monitor blocked request rates and investigate spikes that do not correlate with known attacks -- they are likely false positives triggered by a new application feature or user behavior pattern.
WAF Limitations
WAFs are a valuable defense layer but have fundamental limitations that operators must understand:
- Cannot fix vulnerabilities: a WAF blocks exploit attempts but does not remove the underlying vulnerability. If the WAF is bypassed, misconfigured, or temporarily disabled, the vulnerability is exposed. WAFs are a compensating control, not a remediation.
- Limited against business logic flaws: a WAF cannot detect Insecure Direct Object References (IDOR), broken access control, or business logic abuse (e.g., modifying a shopping cart price). These attacks use syntactically normal requests with valid-looking data -- the attack is in the semantics, not the syntax.
- Encrypted payloads: if the application accepts encrypted or encoded payloads that it decodes server-side, the WAF cannot inspect the decrypted content. Client-side encrypted fields, JWTs with encrypted claims, or application-specific binary protocols are opaque to the WAF.
- API evolution: as applications evolve, new endpoints and parameters appear that the WAF may not have rules for. Without continuous tuning, a WAF's effectiveness degrades over time as the application surface area grows beyond what the rules cover.
- Zero-day attacks: signature-based WAFs cannot detect novel attacks that do not match any existing rule. This is the fundamental limitation of the negative security model. The Log4Shell (CVE-2021-44228) vulnerability demonstrated this vividly -- initial WAF rules were quickly bypassed with obfuscation techniques like
${${lower:j}ndi:${lower:l}dap://...}, requiring dozens of rule updates over several days.
ModSecurity and Coraza: Open-Source WAF Engines
ModSecurity (originally developed by Trustwave SpiderLabs, now part of OWASP) is the most widely deployed open-source WAF engine. It can run as a module for Apache HTTP Server, Nginx (via the ModSecurity-nginx connector), and IIS. ModSecurity provides the rule evaluation engine, logging, and request/response inspection pipeline, while the actual detection logic lives in rule sets (typically OWASP CRS).
Coraza is a modern, Go-based WAF engine that implements the ModSecurity rule language (SecLang) and is compatible with CRS. Coraza is designed for cloud-native deployments: it can run as a standalone reverse proxy, a Go middleware library, or an Envoy external processing filter. Its Go implementation provides better memory safety than ModSecurity's C codebase and simplifies deployment in containerized environments.
WAFs and CORS
WAFs interact with Cross-Origin Resource Sharing (CORS) in important ways. A WAF that blocks requests based on the Origin header can serve as an additional CORS enforcement layer -- rejecting requests from origins that the application does not expect, regardless of whether the application itself checks. However, WAF rules should not add CORS headers to responses (that is the application's responsibility), and WAF rules should be careful not to block legitimate preflight (OPTIONS) requests that browsers send before cross-origin requests.
See It in Action
WAFs protect web applications worldwide, from small business sites to the largest internet properties. Cloud WAF providers like Cloudflare, Akamai, and AWS operate massive anycast networks that inspect billions of HTTP requests daily, blocking millions of attack attempts. The BGP infrastructure that routes traffic to these WAF providers is itself a critical component of the security architecture -- BGP hijacks that divert traffic around the WAF can expose applications to attacks that the WAF would normally block.
Use the god.ad BGP Looking Glass to explore the AS numbers of major WAF providers and see how their anycast networks are connected to the global routing table.