Skip to main content

Web Application Firewall (WAF): Protection Against Web Attacks

Published: February 21, 2026 Updated: May 8, 2026 Larry Qu 14 min read

A Web Application Firewall (WAF) protects applications from malicious traffic and common web attacks. This guide covers WAF concepts, rules, and deployment.

Understanding WAF

What WAF Protects Against

owasp_top_10:
  - "A01:2021 - Broken Access Control"
  - "A02:2021 - Cryptographic Failures"
  - "A03:2021 - Injection"
  - "A04:2021 - Insecure Design"
  - "A05:2021 - Security Misconfiguration"
  - "A06:2021 - Vulnerable Components"
  - "A07:2021 - Auth Failures"
  - "A08:2021 - Data Integrity Failures"
  - "A09:2021 - Logging Failures"
  - "A10:2021 - SSRF"

common_attacks:
  - "SQL Injection"
  - "Cross-Site Scripting (XSS)"
  - "Cross-Site Request Forgery (CSRF)"
  - "Path Traversal"
  - "Command Injection"
  - "LDAP Injection"
  - "XML External Entity (XXE)"

WAF Deployment Modes

deployment_modes:
  - name: "Block Mode"
    description: "Threats are blocked completely"
    
  - name: "Monitor Mode"
    description: "Threats are logged but allowed"
    
  - name: "Learning Mode"
    description: "Traffic patterns are analyzed to create rules"

WAF Architecture and Placement

A WAF sits between the users of a web app and the application servers. It filters, monitors, and blocks web traffic (HTTP). A good WAF is also bidirectional — it should inspect request traffic on its way to an application server in addition to optionally inspecting response traffic being returned to a client.

Where a WAF Lives

Precisely where the WAF lives is flexible: in a public cloud, in a DMZ near the web servers, or even directly on the web servers themselves.

Client → CDN/WAF (edge) → Load Balancer + WAF → App Servers → Databases
              ↓                  ↓                    ↓
         Volumetric           L7 attacks         SQL injection
         DDoS absorbed      filtered here        blocked here

It’s common to see a WAF bundled with a load balancer (reverse proxy). At the point where full Layer 7 load balancing happens, it’s relatively simple to feed the HTTP traffic through a WAF engine and gain its defensive benefits. The load balancing layer can handle TLS termination (feeding only plaintext HTTP into the WAF engine), server load balancing, and high availability.

Defense in Depth

The core principle is that the strongest way to secure a system is to use multiple, independent layers of security — like a multi-layered onion. No single security measure is perfect in the real world. If one or more security measures are bypassed, multiple additional defensive layers remain in place to stop attacks. A WAF is an important defensive layer for web apps exposed to the public internet.

OWASP Core Rule Set (CRS)

The OWASP CRS is the de facto standard set of free and open-source WAF rules, published under the umbrella of the OWASP Foundation. It is used by ModSecurity, Coraza, AWS WAF managed rules, and many commercial WAFs.

Paranoia Levels

CRS rules are spread across four “paranoia level” categories of increasing security:

Level Description False Positives Recommended Use
PL1 Simple, uncontroversial rules Rarely triggered in error Minimum baseline
PL2 Broader range of detection Higher likelihood Default for public web apps
PL3 Even more aggressive rules High High-risk environments
PL4 All rules in play, most aggressive Very high Banking, e-voting, critical infra

Recommended default: PL2 for real-world web applications exposed to the public internet. This gives good protection without overwhelming the team with false positives. PL1 may suffice for a “mandated WAF” scenario (compliance-only). PL3 and PL4 are for specialist, high-paranoia deployments that come with ample time and consultancy needed to make them work correctly.

Enabling the CRS

# ModSecurity + OWASP CRS setup
Include /etc/modsecurity/modsecurity.conf
Include /etc/modsecurity/crs/crs-setup.conf
Include /etc/modsecurity/crs/rules/*.conf

# Set paranoia level (1-4)
SecAction \
  "id:900000, \
   phase:1, \
   nolog, \
   pass, \
   t:none, \
   setvar:tx.executing_paranoia_level=2"

WAF Rules

Rule Types

rule_types:
  - name: "Signature-based"
    description: "Match known attack patterns"
    
  - name: "Behavioral"
    description: "Detect anomalies in traffic patterns"
    
  - name: "Rate-based"
    description: "Limit request frequency"
    
  - name: "Geo-blocking"
    description: "Block traffic from specific regions"
    
  - name: "IP Reputation"
    description: "Block known malicious IPs"

Custom Rules Example

# AWS WAF custom rules

rules:
  - name: "Block SQL Injection"
    statement:
      sqliMatchStatement:
        fieldToMatch:
          body:
            oversizeHandling: MATCH
        samplingPriority: NORMAL
    action:
      block:
    visibilityConfig:
      sampledRequestsEnabled: true

  - name: "Rate Limit"
    statement:
      rateBasedStatement:
        limit: 1000
        aggregateKeyType: IP
    action:
      block:

  - name: "Block XSS"
    statement:
      xssMatchStatement:
        fieldToMatch:
          queryString: {}
        samplingPriority: NORMAL
    action:
      block:

ModSecurity Rules

# ModSecurity rules

# Block SQL Injection
SecRule REQUEST_URI|ARGS "@rx (?i)(\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|ALTER|CREATE|TRUNCATE)\b)" \
    "id:1001,phase:1,deny,status:403,msg:'SQL Injection Attempt'"

# Block XSS
SecRule REQUEST_URI|ARGS|REQUEST_HEADERS "@rx (?i)<script[^>]*>.*?</script>" \
    "id:1002,phase:1,deny,status:403,msg:'XSS Attempt'"

# Block path traversal
SecRule REQUEST_URI "@rx \.\.(\/|\\)" \
    "id:1003,phase:1,deny,status:403,msg:'Path Traversal Attempt'"

# Rate limiting
SecRuleEngine On
SecRequestBodyAccess On
SecPcreMatchLimit 1000
SecPcreMatchLimitRecursion 1000

Implementation Examples

Cloudflare WAF

# Cloudflare WAF via API

import requests

class CloudflareWAF:
    def __init__(self, api_token, zone_id):
        self.base_url = "https://api.cloudflare.com/client/v4"
        self.headers = {
            "Authorization": f"Bearer {api_token}",
            "Content-Type": "application/json"
        }
        self.zone_id = zone_id
    
    def create_firewall_rule(self, name, action, expression):
        """Create WAF rule"""
        url = f"{self.base_url}/zones/{self.zone_id}/firewall/rules"
        
        data = {
            "filter": {
                "expression": expression
            },
            "action": action,
            "priority": 1
        }
        
        response = requests.post(url, json=data, headers=self.headers)
        return response.json()
    
    def block_ip(self, ip):
        """Block specific IP"""
        return self.create_firewall_rule(
            name=f"Block {ip}",
            action="block",
            expression=f"ip.src == {ip}"
        )
    
    def allow_bot(self):
        """Allow known bots"""
        return self.create_firewall_rule(
            name="Allow Good Bots",
            action="allow",
            expression="cf.client.bot"
        )

AWS WAF

# AWS WAF via boto3

import boto3

class AWSWAF:
    def __init__(self, region):
        self.client = boto3.client('wafv2', region_name=region)
        self.scope = "CLOUDFRONT"  # or REGIONAL
    
    def create_ip_set(self, name, addresses):
        """Create IP set for blocking/allowing"""
        response = self.client.create_ip_set(
            Name=name,
            Scope=self.scope,
            Description=f"IP set for {name}",
            Addresses=addresses,
            Tags=[{'Key': 'Environment', 'Value': 'Production'}]
        )
        return response
    
    def create_rule(self, name, statement, action):
        """Create WAF rule"""
        response = self.client.create_rule(
            Name=name,
            Scope=self.scope,
            Rules=[{
                'Name': name,
                'Priority': 0,
                'Statement': statement,
                'Action': {'Block': {}},
                'VisibilityConfig': {
                    'SampledRequestsEnabled': True,
                    'CloudWatchMetricsEnabled': True,
                    'MetricName': name
                }
            }]
        )
        return response

Managed WAF Comparison (2026)

Feature Cloudflare WAF AWS WAF Azure WAF Google Cloud Armor
Managed rules OWASP CRS + Cloudflare managed AWS managed rules + CRS CRS (preview) Preconfigured rules
Deployment CDN edge CloudFront/ALB Application Gateway/Front Door Load balancer/CDN
Pricing $5/mo + $0.50/rule $5/mo + $1/rule + data ~$30/mo + traffic Per request
Bot management Excellent Basic Basic Via reCAPTCHA
API protection Schema validation API Gateway integration Front Door Cloud Armor + Apigee
ML/AI detection Behavioral + threat score Bot Control Anomaly scoring ML-based
Rate limiting Built-in Rate-based rules Custom rules Edge security policies
Virtual patching Yes Yes Yes Yes

Choosing a Managed WAF

Scenario Recommended Why
Public web app behind CDN Cloudflare WAF Best edge protection, bot management
AWS-native stack AWS WAF Native integration, managed rule groups
Azure enterprise Azure WAF Front Door integration, compliance
GCP with global load balancing Cloud Armor Native GCP, reCAPTCHA integration

Virtual Patching

Consider a situation where a backend web application has a known vulnerability but cannot be patched. This happens when: the vendor hasn’t released a fix yet, a policy requires waiting for a maintenance window, or the application is legacy and unsupported.

Virtual patches are custom WAF rules that detect and block attack attempts targeting the known vulnerability. If the nature of the vulnerability is well understood, a virtual patch can secure access to the vulnerable application until it can be fully patched.

# Virtual patch example: block POST to a vulnerable endpoint
- name: "VirtualPatch-API-FOO"
  action: block
  statement:
    andStatement:
      statements:
        - byteMatchStatement:
            searchString: "/api/foo"
            fieldToMatch:
              uriPath: {}
        - statement:
            andStatement:
              statements:
                - labelMatchStatement:
                    scope: LABEL_NAMESPACE
                    key: "awswaf:managed:aws:bot-control:bot:category:monitored"
  visibilityConfig:
    sampledRequestsEnabled: true

WAF False Positive Management

When a legitimate HTTP request causes WAF rules to trigger in error, it’s called a false positive. False positives cause poor user experience, make it difficult to detect real attacks, and potentially cause compliance issues.

Reducing False Positives

  1. Understand the web traffic — know the technologies in use, which HTTP methods are allowed, which file extensions are legitimate
  2. Disable irrelevant rule categories — if the app doesn’t use PHP or Java, disable those rule groups
  3. Enable request body inspection only where needed — JSON/XML APIs benefit, but keep body size limits low (16KB is sensible for production)
  4. Use automated false positive detection — tools that inspect WAF logs and flag the most likely false positive candidates
  5. Deploy in monitor mode first — observe rule triggers against legitimate traffic before enabling block mode

Testing Your WAF

It’s crucial to test an application through a WAF. Running an automated test suite after updating a web application may flag new false positives caused by new or changed features. Even a simple test answers the common question of “Is my WAF working?”:

# Simple WAF test — triggers Unix command injection rules
curl "https://my-app.example.com/foo?bar=/bin/bash"

# If the WAF is working, a log entry flags "/bin/bash"
# against the test machine's IP address

API Security with WAF

Traditional WAF rule sets were designed for HTML web applications. Modern applications are predominantly API-driven, requiring different protections. When defending APIs, ensure JSON and XML payloads are parsed and inspected.

API WAF Requirements

Requirement Implementation
Schema validation Validate request/response against OpenAPI schema
Authentication enforcement Require tokens, validate JWT
Rate limiting per client API keys, OAuth scopes
Payload inspection JSON/XML parsing, body size limits
Endpoint-specific rules Per-path protections
Idempotency support Allow retry-safe write paths

WAF Bypass Attacks

A WAF can be bypassed. Understanding common bypass techniques helps you build stronger defenses:

Bypass Technique Description Defense
Encoding tricks Double URL encoding, Unicode obfuscation Decode payloads before inspection
Case variation Mixed-case SQL keywords Case-insensitive rule matching
Null bytes Injecting %00 to truncate Handle null byte rejection
HTTP parameter pollution Duplicate parameters confuse parsers Normalize parameter parsing
Content-type switching Change to multipart to skip body inspection Inspect all content types
WAF-parser mismatch Exploit differences between WAF and app parsers Use same parser as app
Protocol smuggling CL.TE / TE.CL desync attacks HTTP/2, strict request validation

Mitigating Bypass Risk

  1. Use a WAF that decodes and normalizes payloads before inspection
  2. Enable body inspection for all content types
  3. Keep the WAF parser consistent with your application framework
  4. Deploy defense-in-depth — never rely solely on the WAF
  5. Run regular bypass testing (fuzzing, payload mutation)
  6. Monitor for encoding anomalies in traffic

WAF Performance Impact

A poorly tuned WAF can add significant latency. Measure and optimize:

Factor Impact Optimization
Rule count More rules = slower Use managed rule groups, disable irrelevant
Body inspection Parsing payloads is expensive Limit body size, selective inspection
Regex complexity Catastrophic backtracking Use bounded regexes, linear algorithms
Log volume Logging every request Sample logs, log only blocked requests
Deployment location Edge vs origin Offload to CDN edge
# Performance targets
waf_performance:
  p50_latency_overhead_ms: 5
  p95_latency_overhead_ms: 15
  max_payload_inspection_kb: 16
  rule_timeout_ms: 100
  request_sample_rate: 0.05

WAF Logging and Compliance

What to Log

Event Required Retention
Blocked requests Yes 90 days minimum
Rule triggers (monitor mode) Yes 30 days
Rate limit violations Yes 30 days
Bot detections Yes 90 days
Bypass attempts Yes 1 year
Allowed requests (sampled) Optional 7 days

Compliance Frameworks

Framework WAF Requirement
PCI DSS WAF or equivalent for all public web apps
SOC 2 Access control + web app firewall controls
ISO 27001 A.14 application security controls
HIPAA EPHI protection for web apps
NIST 800-53 SC-7 boundary protection

WAF Deployment Configurations

High Availability WAF

        Internet
           |
      [CDN/WAF Edge 1] -- [CDN/WAF Edge 2]
           |                    |
      [Load Balancer] ---- [Load Balancer]
           |                    |
      [App Server A]       [App Server B]

WAF Testing in CI/CD

# GitHub Action: WAF rule testing
name: WAF Rules Test
on: [pull_request]

jobs:
  waf-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy test environment
        run: docker compose up -d
      - name: Run attack simulations
        run: |
          ./tests/waf-attack-test.sh  # sends malicious payloads
          ./tests/waf-normal-test.sh  # sends legitimate traffic
      - name: Verify no false negatives
        run: python tests/check-waf-log.py --expect-blocked
      - name: Verify no false positives
        run: python tests/check-waf-log.py --expect-allowed

WAF Best Practices

# WAF best practices

deployment:
  - "Start in learning/monitor mode"
  - "Test in monitor mode before enabling blocking"
  - "Tune rules to reduce false positives"
  - "Use managed rule groups when possible"
  - "Require per-rule, per-path exception capability"
  - "Evaluate API schema validation, not just web rules"
  - "Keep rules updated"
  - "Assess managed rule update cadence against change management"

monitoring:
  - "Review blocked requests regularly"
  - "Set up alerts for spikes"
  - "Track false positive rates"
  - "Monitor performance impact"
  - "Model total cost including logging, analytics, services"

rules:
  - "Start with OWASP Core Rules"
  - "Add custom rules for specific needs"
  - "Review and update regularly"
  - "Test rules before deploying"
  - "Use Deprecation/Sunset headers for API changes"

WAF Implementation Checklist

  • Deploy in monitor mode first (1-2 weeks of baseline traffic)
  • Review false positives and tune rules
  • Enable request body inspection for API payloads
  • Set paranoia level (PL2 default)
  • Configure rate limiting rules
  • Enable IP reputation / bot management
  • Set up alerting for rule triggers and spikes
  • Create virtual patches for known unpatched vulnerabilities
  • Document incident response for WAF bypasses
  • Schedule regular rule reviews and updates

WAF Rule Examples by Attack Type

SQL Injection

# Block SQL injection patterns
- name: "SQLi-Block"
  action: block
  statement:
    sqliMatchStatement:
      fieldToMatch:
        body: { oversizeHandling: MATCH }
      textTransformations:
        - priority: 0
          type: "URL_DECODE"
        - priority: 1
          type: "HTML_ENTITY_DECODE"

Cross-Site Scripting (XSS)

# Block XSS patterns
- name: "XSS-Block"
  action: block
  statement:
    xssMatchStatement:
      fieldToMatch:
        queryString: {}
      textTransformations:
        - priority: 0
          type: "URL_DECODE"
        - priority: 1
          type: "HTML_ENTITY_DECODE"

Path Traversal

# Block path traversal
- name: "PathTraversal-Block"
  action: block
  statement:
    byteMatchStatement:
      searchString: "../"
      searchStringType: "EXACT"
      fieldToMatch:
        uriPath: {}

Command Injection

# Block command injection
- name: "CommandInjection-Block"
  action: block
  statement:
    regexPatternSetReferenceStatement:
      arn: "arn:aws:wafv2:.../regex-pattern-set/command-injection"
Resource Type URL
OWASP WAF Evaluation Criteria Guide waf.owasp.org
ModSecurity Open-source WAF engine github.com/owasp-modsecurity
Coraza Next-gen Go WAF engine coraza.io
OWASP CRS Detection rules coreruleset.org
Cloudflare WAF Docs Documentation developers.cloudflare.com
AWS WAF Docs Documentation aws.amazon.com/waf

Conclusion

WAF is essential for web application security:

  • Deploy in stages: Start with monitoring, then block
  • Tune continuously: Reduce false positives
  • Layer with other security: WAF is one layer of defense
  • Use OWASP CRS: The de facto open-source ruleset, at PL2 by default
  • Test regularly: Automated test suites catch new false positives
  • Virtual patch: Protect unpatched vulnerabilities with custom rules

Use managed rules from Cloudflare, AWS, Azure for best protection. A WAF is not a replacement for patching web application vulnerabilities — it’s a complementary layer that detects and blocks attacks while you keep applications patched and hardened.

WAF Maturity Model

Level Capabilities Testing Monitoring
1: Basic Default rules, block mode None Manual log review
2: Tuned CRS PL2, custom rules Occasional Alert on spikes
3: Managed Managed rule groups, bot detection Regular test suite Automated alerts
4: Optimized API protection, virtual patches CI/CD testing False positive analysis
5: Adaptive ML detection, auto-tuning Continuous fuzzing Full observability

WAF Summary Checklist

  • OWASP CRS enabled at PL2
  • Monitor mode baseline captured
  • Custom rules for app-specific threats
  • Managed rule groups subscribed
  • Rate limiting configured
  • Bot management enabled
  • Virtual patches for known CVEs
  • CI/CD WAF testing pipeline
  • Logging and alerting configured
  • Regular rule review scheduled

WAF Rule Design Patterns

Pattern 1: Default Allow with Blocklist

# Allow all traffic, block known bad patterns
default_action: allow
rules:
  - name: "Block SQLi"
    action: block
    match: "sqli"
  - name: "Block XSS"
    action: block
    match: "xss"

Pattern 2: Default Block with Allowlist

# Block everything, allow specific paths
default_action: block
allowlist:
  - "/api/public"
  - "/health"
  - "/assets/*"

Pattern 3: Progressive Enforcement

# Stages: monitor → challenge → block
stages:
  - mode: "monitor"
    duration: "1-2 weeks"
    action: "log only"
  - mode: "challenge"
    duration: "1 week"
    action: "js_challenge on suspicious"
  - mode: "block"
    duration: "continuous"
    action: "block confirmed attacks"

WAF Metrics and Alerting

Metric Alert Threshold Critical
Blocked requests > 2x baseline > 10x baseline
False positive rate > 1% > 5%
Rule trigger count Spikes Sustained elevation
WAF latency > 15ms p95 > 50ms p95
Bot detection New bot families Major botnet activity
Bypass attempts > 10/day > 100/day
Managed rule updates Stale > 30 days Stale > 90 days

WAF Comparison: Cloud vs On-Premise

Factor Cloud WAF On-Premise WAF
Deployment Edge/CDN, global Data center, appliance
Scaling Automatic Manual capacity
Latency Minimal (edge) Low (same network)
Cost Usage-based License + hardware
Maintenance Vendor-managed In-house
Visibility Provider dashboard Full control
Compliance Provider certifications Full data control
Best for Public web apps Regulated, air-gapped

WAF with API Gateways

Integrate WAF with API gateways for comprehensive API protection:

# API Gateway + WAF integration (AWS)
api_gateway_waf:
  stage: "prod"
  waf_acl: "api-protection"
  rules:
    - managed_rule: "AWSManagedRulesCommonRuleSet"
      priority: 10
    - managed_rule: "AWSManagedRulesSQLiRuleSet"
      priority: 20
    - managed_rule: "AWSManagedRulesBotControlRuleSet"
      priority: 30
    - custom_rule: "rate-limit-per-key"
      priority: 40
  logging:
    redacted_fields:
      - "authorization"
      - "x-api-key"

Frequently Asked Questions

Q: What is the difference between a WAF and a next-generation firewall? A: A WAF inspects HTTP/HTTPS traffic at Layer 7 (application), protecting against web attacks like SQL injection and XSS. A next-generation firewall (NGFW) operates at network layers (L3-L7), providing stateful filtering, intrusion prevention, and application awareness. They complement each other: NGFW at the perimeter, WAF in front of web apps.

Q: Can a WAF replace patching web application vulnerabilities? A: No. A WAF is a compensating control, not a replacement for patching. Virtual patches can protect unpatched vulnerabilities temporarily, but keeping applications patched is essential.

Q: What is the OWASP Core Rule Set and should I use it? A: The CRS is a free, open-source ruleset for WAF engines like ModSecurity and Coraza. It’s the de facto standard for WAF rule detection. Yes, use it — it covers the OWASP Top 10 and common attack patterns.

Q: How do I handle WAF bypass attacks? A: Use a WAF that decodes and normalizes payloads, enable body inspection for all content types, keep parsers consistent with the application, deploy defense-in-depth, and run regular bypass testing.

Q: How does WAF handle API security differently from web application security? A: APIs require schema validation, authentication enforcement, per-client rate limiting, and payload inspection of JSON/XML — beyond the HTML-focused rules of traditional WAFs. Modern WAFs and API gateways provide these API-specific protections.

Comments

👍 Was this article helpful?