Web Application Firewall (WAF)
The WAF domain tests rule authoring and rule ordering: given a request and a rule set, can you say exactly what happens? Cloudflare's WAF combines managed rulesets, custom rules, and rate limiting rules that evaluate in a defined order.
Building blocks
- Cloudflare Managed Ruleset – curated rules maintained by Cloudflare and updated as vulnerabilities emerge; each rule has its own action and tags.
- OWASP Core Ruleset – the CRS port, scored against an anomaly threshold. Paranoia level PL1–PL4 controls how many rules run: PL1 is the default with the lowest false-positive rate; PL3–PL4 catch more but block more legitimate traffic.
- Custom rules – written in Cloudflare's wirefilter expression language, for example
http.request.uri.path contains "/admin" and ip.src ne 203.0.113.10. - Rate limiting rules – count requests over a period and act on the excess.
Evaluation
Custom rules evaluate in the order you set, reorderable in the dashboard. A terminating action - Block, Challenge, Managed Challenge, JS Challenge - ends evaluation for that request. Log does not terminate. Skip is not a synonym for allow; it suppresses specified remaining components, for example skipping the OWASP ruleset on a path that legitimately submits code-like payloads. Useful fields include ip.src, http.request.method, http.request.uri.path, http.request.headers["user-agent"], http.host, and cf.bot_management.score; useful functions include lower(), concat(), len(), and matches for regular expressions.
Worked example
Requirement: block POSTs to /wp-login.php from everywhere except two office IPs, without breaking a monitoring probe. Rule 1 (first): http.request.method eq "POST" and http.request.uri.path eq "/wp-login.php" and ip.src ne 198.51.100.7 and ip.src ne 198.51.100.8 → Block. Because evaluation is ordered, the probe needs either an extra ip.src ne clause or a preceding Skip rule scoped to the probe IP and path. Deploy with Log first, verify in Security Events, then switch to Block.
Traps
- Assuming rules run in creation order rather than the displayed, reorderable order.
- Treating Skip as equivalent to Allow; its effect depends on which components you select.
- Jumping straight to PL4 or Block instead of logging first.
- Forgetting that managed rulesets and custom rules both apply - a custom Block does not disable managed rules.