Loading learning content...
A Web Application Firewall (WAF) sits between the internet and your web applications, inspecting every HTTP request before it reaches your servers. It's not just a DDoS mitigation tool—it's a comprehensive security layer that protects against the OWASP Top 10 vulnerabilities, application-specific threats, and targeted attacks that would slip past network-level defenses.
While rate limiters count requests and bot detectors analyze behavior, WAFs examine content. They understand HTTP deeply—parsing headers, cookies, request bodies, URLs, and responses to detect and block malicious payloads, attack patterns, and policy violations.
Implementing a WAF effectively requires understanding its architecture, configuring rules appropriately, managing false positives, and integrating it into your overall security posture. This page covers the complete WAF implementation journey.
By the end of this page, you will understand WAF architecture patterns, rule types and configuration, deployment models (cloud vs. on-premises), tuning strategies to minimize false positives, and operational practices for maintaining WAF effectiveness over time.
A WAF operates as a reverse proxy, receiving all HTTP traffic before your application servers. It inspects each request against configured rules and makes one of several decisions:
WAF Decision Outcomes:
Processing Pipeline:
WAFs process requests through multiple stages:
Request Parsing:
Before rules can evaluate a request, the WAF must parse it:
Normalization:
Attackers use encoding tricks to evade rules. Normalization converts various encodings to canonical form:
%3Cscript%3E → <script>eval(\x65\x76\x61\x6c) → eval(eval)SE/**/LECT → SELECT (SQL comment evasion)Without normalization, rules must account for infinite encoding variations. With normalization, rules match the underlying intent.
Attackers continuously develop techniques to evade WAF rules. Normalization alone isn't sufficient—WAF vendors constantly update their parsers and rules to catch new evasion techniques. This is why managed WAF services provide value through ongoing threat research.
WAF rules fall into several categories, each addressing different threat types:
1. Signature-Based Rules (Pattern Matching):
Matching known attack patterns in requests:
UNION SELECT, ' OR 1=1)<script>, javascript:); rm -rf, | cat /etc/passwd)../../../etc/passwd)2. Anomaly Detection Rules:
Identifying requests that deviate from expected behavior:
3. Rate-Based Rules:
Triggering on request frequency thresholds:
4. Geo/IP Rules:
Decisions based on traffic origin:
| Category | Threat Type | Detection Method | False Positive Risk |
|---|---|---|---|
| SQL Injection | SQLI attacks | Signature + Anomaly | Medium |
| Cross-Site Scripting | XSS attacks | Signature + Context | Medium-High |
| Remote Code Execution | RCE/Command injection | Signature | Low |
| Local File Inclusion | LFI/Path traversal | Signature + Path analysis | Low |
| Protocol Enforcement | HTTP violations | Anomaly | Low |
| Scanner Detection | Automated scans | Fingerprinting | Low |
| Bot Protection | Malicious bots | Behavioral + Fingerprint | Medium |
12345678910111213141516171819202122232425262728293031323334353637383940
# SQL Injection Detection RuleSecRule REQUEST_COOKIES|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* \ "@rx (?i:(?:(?:s)elect\s+(?:(?:(?:all|distinct)\s+)?(?:\*|[\w\s,]+))?(?:\s+(?:into|from)))|(?:(?:union)(?:\s+(?:all)?)?\s+(?:select))))" \ "id:942100,\ phase:2,\ block,\ t:none,t:utf8toUnicode,t:urlDecodeUni,t:removeNulls,t:lowercase,\ msg:'SQL Injection Attack Detected via libinjection',\ logdata:'Matched Data: %{MATCHED_VAR} found within %{MATCHED_VAR_NAME}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-sqli',\ tag:'OWASP_CRS',\ severity:'CRITICAL'" # XSS Detection RuleSecRule REQUEST_COOKIES|REQUEST_COOKIES_NAMES|ARGS_NAMES|ARGS|XML:/* \ "@rx (?i:<script[^>]*>[\\s\\S]*?<\\/script[^>]*>|<script[^>]*>)" \ "id:941100,\ phase:2,\ block,\ t:none,t:utf8toUnicode,t:urlDecodeUni,t:htmlEntityDecode,t:jsDecode,t:cssDecode,t:removeNulls,\ msg:'XSS Attack Detected via libinjection',\ tag:'attack-xss',\ severity:'CRITICAL'" # Rate Limiting RuleSecRule IP:REQUESTS_RATE "@gt 100" \ "id:900001,\ phase:1,\ block,\ msg:'Rate limit exceeded - too many requests from IP',\ tag:'rate-limiting'" # Geo Blocking RuleSecGeoLookupDB /path/to/GeoLite2-Country.mmdbSecRule REMOTE_ADDR "@geoLookup" "chain,id:999001,phase:1,block" SecRule GEO:COUNTRY_CODE "!@within US CA GB DE FR" \ "msg:'Access denied for country: %{GEO:COUNTRY_CODE}'"The OWASP ModSecurity Core Rule Set (CRS) is the industry-standard open-source rule set used by many commercial and open-source WAFs. Understanding CRS is essential because most WAFs either use it directly or derive their rules from it.
CRS Design Philosophy:
Rather than trying to match every possible attack variant, CRS uses anomaly scoring:
This approach reduces false positives—a single match might be benign, but multiple suspicious indicators likely indicate an attack.
123456789101112131415161718192021222324
# CRS Configuration (crs-setup.conf) # Anomaly scoring mode (recommended)SecAction "id:900000,phase:1,nolog,pass,t:none,\ setvar:tx.blocking_paranoia_level=1,\ setvar:tx.detection_paranoia_level=1" # Anomaly score thresholds# Start conservative (higher thresholds = fewer blocks)SecAction "id:900110,phase:1,nolog,pass,t:none,\ setvar:tx.inbound_anomaly_score_threshold=10,\ setvar:tx.outbound_anomaly_score_threshold=5" # Paranoia levels:# Level 1: Minimal false positives, catches obvious attacks# Level 2: Moderate rules, some false positives possible# Level 3: Aggressive, requires tuning for most applications# Level 4: Very aggressive, expect many false positives # Rule exclusion example (tuning for false positives)# Exclude specific parameter from SQL injection rulesSecRule REQUEST_URI "@beginsWith /api/search" \ "id:1000,phase:1,nolog,pass,\ ctl:ruleRemoveTargetById=942100;ARGS:query"Begin with CRS Paranoia Level 1 in blocking mode, or Level 2 in detection mode. Analyze logs for false positives, create exclusions, then gradually increase sensitivity. Jumping to high paranoia levels without tuning will block legitimate traffic.
WAFs can be deployed in several architectures, each with tradeoffs:
1. Cloud WAF (SaaS/CDN-Integrated):
Providers: Cloudflare, AWS WAF, Azure WAF, Akamai
2. Reverse Proxy WAF (On-Premises/Cloud IaaS):
Software: ModSecurity, NGINX Plus, F5
3. Embedded WAF (Application-Level):
Libraries integrated into application code
| Factor | Cloud WAF | Reverse Proxy | Embedded |
|---|---|---|---|
| Setup Complexity | Low | Medium | High |
| Operational Burden | Low | High | Medium |
| Latency Impact | Minimal (edge) | Single hop | None |
| Customization | Limited | Full | Full |
| Cost Model | Per-request | Infrastructure | Development |
| DDoS Integration | Built-in | Separate | None |
| SSL Termination | Provider | Your control | Your control |
Many organizations use multiple WAF layers: cloud WAF at the edge for volumetric protection and managed rules, plus reverse proxy or embedded WAF closer to the application for custom, application-specific rules. Each layer catches attacks the others might miss.
AWS WAF integrates with CloudFront, Application Load Balancer, and API Gateway. Understanding its configuration demonstrates cloud WAF patterns applicable across providers.
AWS WAF Concepts:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
# AWS WAF Web ACL with comprehensive protectionresource "aws_wafv2_web_acl" "main" { name = "production-web-acl" description = "Production WAF with DDoS and attack protection" scope = "REGIONAL" # or CLOUDFRONT for edge default_action { allow {} } # AWS Managed Rules - Bot Control rule { name = "AWSManagedRulesBotControlRuleSet" priority = 1 override_action { none {} } statement { managed_rule_group_statement { vendor_name = "AWS" name = "AWSManagedRulesBotControlRuleSet" managed_rule_group_configs { aws_managed_rules_bot_control_rule_set { inspection_level = "COMMON" } } } } visibility_config { cloudwatch_metrics_enabled = true metric_name = "BotControl" sampled_requests_enabled = true } } # AWS Managed Rules - Common Attack Protection rule { name = "AWSManagedRulesCommonRuleSet" priority = 2 override_action { none {} } statement { managed_rule_group_statement { vendor_name = "AWS" name = "AWSManagedRulesCommonRuleSet" # Exclude rules that cause false positives rule_action_override { action_to_use { count {} } name = "SizeRestrictions_BODY" } } } visibility_config { cloudwatch_metrics_enabled = true metric_name = "CommonRules" sampled_requests_enabled = true } } # AWS Managed Rules - SQL Injection rule { name = "AWSManagedRulesSQLiRuleSet" priority = 3 override_action { none {} } statement { managed_rule_group_statement { vendor_name = "AWS" name = "AWSManagedRulesSQLiRuleSet" } } visibility_config { cloudwatch_metrics_enabled = true metric_name = "SQLi" sampled_requests_enabled = true } } # Rate-based rule for DDoS protection rule { name = "RateLimit" priority = 10 action { block {} } statement { rate_based_statement { limit = 2000 aggregate_key_type = "IP" scope_down_statement { not_statement { statement { ip_set_reference_statement { arn = aws_wafv2_ip_set.allowlist.arn } } } } } } visibility_config { cloudwatch_metrics_enabled = true metric_name = "RateLimit" sampled_requests_enabled = true } } # Geo-blocking rule rule { name = "GeoBlock" priority = 20 action { block {} } statement { geo_match_statement { country_codes = ["KP", "IR", "SY"] # North Korea, Iran, Syria } } visibility_config { cloudwatch_metrics_enabled = true metric_name = "GeoBlock" sampled_requests_enabled = true } } # Custom rule - Block specific User-Agents rule { name = "BlockBadUserAgents" priority = 30 action { block {} } statement { or_statement { statement { byte_match_statement { search_string = "curl" positional_constraint = "CONTAINS" field_to_match { single_header { name = "user-agent" } } text_transformation { priority = 0 type = "LOWERCASE" } } } statement { byte_match_statement { search_string = "python-requests" positional_constraint = "CONTAINS" field_to_match { single_header { name = "user-agent" } } text_transformation { priority = 0 type = "LOWERCASE" } } } } } visibility_config { cloudwatch_metrics_enabled = true metric_name = "BadUserAgents" sampled_requests_enabled = true } } visibility_config { cloudwatch_metrics_enabled = true metric_name = "ProductionWebACL" sampled_requests_enabled = true } tags = { Environment = "production" Application = "web" }}The biggest WAF operational challenge isn't blocking attacks—it's not blocking legitimate traffic. Every false positive is a frustrated user, a lost sale, or a broken integration. Effective WAF operation requires continuous tuning.
The Tuning Workflow:
1234567891011121314151617181920212223242526272829303132
# Common exclusion patterns for false positive management # Exclusion Type 1: Remove entire rule for specific URL# The search API sends user-provided query strings that match SQL patternsSecRule REQUEST_URI "@beginsWith /api/search" \ "id:1001,phase:1,nolog,pass,\ ctl:ruleRemoveById=942100" # Exclusion Type 2: Remove rule for specific parameter# The 'content' field in blog posts may contain HTML (expected)SecRule REQUEST_URI "@beginsWith /api/posts" \ "id:1002,phase:1,nolog,pass,\ ctl:ruleRemoveTargetById=941100;ARGS:content" # Exclusion Type 3: Remove rule for specific IP (internal tools)SecRule REMOTE_ADDR "@ipMatch 10.0.0.0/8" \ "id:1003,phase:1,nolog,pass,\ ctl:ruleRemoveById=949110" # Exclusion Type 4: Allowlist specific request pattern# Webhooks from payment provider have large bodiesSecRule REQUEST_URI "@rx ^/webhooks/(stripe|paypal)$" \ "id:1004,phase:1,nolog,pass,\ chain" SecRule REMOTE_ADDR "@ipMatch 52.89.214.238,54.187.174.169" \ "ctl:ruleRemoveById=920350" # Exclusion Type 5: Raise threshold for specific URL# Admin panel is trusted; higher toleranceSecRule REQUEST_URI "@beginsWith /admin" \ "id:1005,phase:1,nolog,pass,\ setvar:tx.inbound_anomaly_score_threshold=20"Every exclusion is a potential security gap. If you exclude SQL injection rules for /api/search, attackers may attempt SQL injection there. Minimize exclusion scope, and consider whether application changes could eliminate the need for exclusions.
WAF effectiveness depends on proper logging and monitoring. Without visibility, you can't tune rules, detect attacks, or prove compliance.
What to Log:
Metrics to Monitor:
| Metric | Purpose | Alert Threshold |
|---|---|---|
| Block Rate | Detect attack spikes or false positive issues | 3σ above baseline |
| Rule Match Distribution | Identify which rules are most active | Trend analysis |
| Latency Impact | Ensure WAF isn't degrading performance | 50ms added latency |
| Error Rate | Detect WAF processing failures | 0.1% error rate |
| Challenge Success Rate | Bot vs human CAPTCHA solving | <50% success = attack |
| Unique IPs Blocked | Scale of attack vs false positives | Sudden spikes |
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
# Alert on sudden spike in blocked requestsresource "aws_cloudwatch_metric_alarm" "waf_block_spike" { alarm_name = "WAF-BlockRateSpike" comparison_operator = "GreaterThanThreshold" evaluation_periods = 2 metric_name = "BlockedRequests" namespace = "AWS/WAFV2" period = 300 statistic = "Sum" threshold = 1000 alarm_description = "High volume of blocked requests may indicate attack or false positives" dimensions = { WebACL = aws_wafv2_web_acl.main.name Region = "us-east-1" } alarm_actions = [aws_sns_topic.security_alerts.arn]} # Alert on specific rule group triggeringresource "aws_cloudwatch_metric_alarm" "waf_sqli_detections" { alarm_name = "WAF-SQLi-Detections" comparison_operator = "GreaterThanThreshold" evaluation_periods = 1 metric_name = "CountedRequests" namespace = "AWS/WAFV2" period = 60 statistic = "Sum" threshold = 50 alarm_description = "SQL injection attempts detected" dimensions = { WebACL = aws_wafv2_web_acl.main.name Rule = "AWSManagedRulesSQLiRuleSet" Region = "us-east-1" } alarm_actions = [aws_sns_topic.security_alerts.arn]} # Log WAF decisions to S3/CloudWatchresource "aws_wafv2_web_acl_logging_configuration" "main" { log_destination_configs = [aws_kinesis_firehose_delivery_stream.waf_logs.arn] resource_arn = aws_wafv2_web_acl.main.arn logging_filter { default_behavior = "DROP" filter { behavior = "KEEP" condition { action_condition { action = "BLOCK" } } requirement = "MEETS_ANY" } filter { behavior = "KEEP" condition { action_condition { action = "COUNT" } } requirement = "MEETS_ANY" } }}Attackers actively attempt to bypass WAF protection. Understanding bypass techniques helps design more robust defenses.
Common Bypass Techniques:
1. Encoding Evasion:
%3Cscript%3E%253Cscript%253E<script> using Unicode points<ScRiPt>2. Comment Injection:
SEL/**/ECT or SELECT/**/password<scr<!--comment-->ipt>3. Protocol-Level Tricks:
4. Semantic Evasion:
<img/src=x onerror=alert(1)> instead of <script>javascript:alert(1) in various contextsNo WAF catches 100% of attacks. Skilled attackers with time can often find bypasses. WAF is a critical layer but must be combined with secure coding practices, input validation in applications, output encoding, and secure architecture. Defense in depth is essential.
WAF implementation is both a technical deployment and an ongoing operational practice. The WAF must be tuned to your specific application while remaining effective against evolving threats.
What's Next:
WAFs are most effective when integrated with CDN infrastructure. The next page explores CDN-based DDoS mitigation, combining global distribution, caching, and intelligent traffic routing for comprehensive protection against attacks at scale.
You now understand WAF architecture, rule configuration, deployment models, and operational best practices. WAFs provide essential application-layer protection when properly implemented and continuously maintained.