Claude
Skills
Sign in
Back

waf

Included with Lifetime
$97 forever

Web Application Firewall configuration. Covers ModSecurity v3 with Nginx and Cloudflare WAF: managed rulesets, custom rules, rate limiting, and tuning. USE WHEN: user mentions "waf", "web application firewall", "modsecurity", "owasp crs", "core rule set", "cloudflare waf", "cloudflare firewall rules", "cloudflare rate limiting", "cloudflare custom rules", "modsecurity nginx", "secruleengine", "false positive waf", "waf exclusion", "waf bypass", "cloudflare bot fight mode", "cloudflare managed ruleset", "waf tuning" DO NOT USE FOR: Network-layer firewalls (iptables, nftables, ufw) — those are not WAF, DDoS volumetric protection at ISP level, API authentication / authorization — use `authentication` skill, Input validation in application code — use application-level validation

Backend & APIs

What this skill does

# WAF Core Knowledge

## WAF Layers

```
Internet
   │
   ▼
[ Cloudflare WAF ]  ← Layer 1: Edge WAF (managed rulesets, rate limits, bot protection)
   │
   ▼
[ Load Balancer / Nginx ]
   │
   ▼
[ ModSecurity + CRS ]  ← Layer 2: Host WAF (inline with web server)
   │
   ▼
[ Application ]
```

Use both layers for defense in depth. Cloudflare is cheaper per request but Nginx +
ModSecurity gives you more visibility on the host and works without Cloudflare.

---

## ModSecurity v3 with Nginx

### Install ModSecurity and Nginx Connector

```bash
# Ubuntu 22.04 / 24.04
sudo apt update
sudo apt install -y libmodsecurity3 libmodsecurity-dev

# Install Nginx ModSecurity connector
# Option A: compile Nginx with connector (recommended for full control)
# Get connector source, then compile as dynamic module
git clone --depth 1 https://github.com/owasp-modsecurity/ModSecurity-nginx.git /tmp/modsecurity-nginx
NGINX_VER=$(nginx -v 2>&1 | grep -oP '[\d.]+')
wget http://nginx.org/download/nginx-${NGINX_VER}.tar.gz -P /tmp
cd /tmp && tar -xzf nginx-${NGINX_VER}.tar.gz
cd nginx-${NGINX_VER} && ./configure --with-compat --add-dynamic-module=/tmp/modsecurity-nginx
make modules
sudo cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules/

# Option B: use pre-built package (distro-specific)
# Ubuntu PPA often provides: nginx-extras with modsecurity bundled

# Load module in nginx.conf
echo 'load_module modules/ngx_http_modsecurity_module.so;' | sudo tee /etc/nginx/modules-enabled/50-mod-modsecurity.conf
```

### Download OWASP Core Rule Set

```bash
CRS_VERSION=4.7.0
wget https://github.com/coreruleset/coreruleset/archive/refs/tags/v${CRS_VERSION}.tar.gz
sudo tar -xzf v${CRS_VERSION}.tar.gz -C /etc/modsecurity/
sudo ln -s /etc/modsecurity/coreruleset-${CRS_VERSION} /etc/modsecurity/crs

# Copy default configs
sudo cp /etc/modsecurity/crs/crs-setup.conf.example /etc/modsecurity/crs/crs-setup.conf
sudo cp /usr/share/modsecurity-crs/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
```

### Core `modsecurity.conf` Settings

```apacheconf
# /etc/modsecurity/modsecurity.conf

# CRITICAL: Set to On in production, DetectionOnly to test
SecRuleEngine On
# SecRuleEngine DetectionOnly    # Log but do not block — use during initial tuning

# Request body inspection
SecRequestBodyAccess On
SecRequestBodyLimit 13107200        # 12.5 MB max request body
SecRequestBodyNoFilesLimit 131072   # 128 KB for non-file content
SecRequestBodyLimitAction Reject    # Reject requests exceeding body limit

# Response body inspection
SecResponseBodyAccess On
SecResponseBodyMimeType text/plain text/html text/xml application/json
SecResponseBodyLimit 524288         # 512 KB

# Audit log — CRITICAL for incident investigation
SecAuditEngine RelevantOnly         # Log only blocked/suspicious requests
# SecAuditEngine On                 # Log everything (very verbose, use only for debugging)
SecAuditLog /var/log/modsecurity/audit.log
SecAuditLogParts ABCDEFHIJKZ        # What to include in audit log
SecAuditLogType Serial
SecAuditLogStorageDir /var/log/modsecurity/data/

# Debug log (level 0-9, 0=off, 9=maximum verbosity)
SecDebugLog /var/log/modsecurity/debug.log
SecDebugLogLevel 0                  # 0 in production; set 3-5 for debugging

# Temporary files
SecTmpDir /tmp/modsecurity/
SecDataDir /tmp/modsecurity/

# Upload handling
SecUploadDir /tmp/modsecurity/upload/
SecUploadKeepFiles Off

# Sensor ID (for cluster deployments)
SecSensorId nginx-waf-01

# Default action: log + pass (rules set block action explicitly)
SecDefaultAction "phase:1,log,auditlog,pass"
```

### CRS Setup (`crs-setup.conf` Key Settings)

```apacheconf
# /etc/modsecurity/crs/crs-setup.conf

# Paranoia Level (1-4):
# 1 = Baseline protection, very few false positives (recommended start)
# 2 = More rules, some FPs — good for APIs with known input patterns
# 3 = Strict, significant tuning required
# 4 = Maximum, expect many FPs — only for high-security apps after extensive tuning
SecAction \
  "id:900000, \
   phase:1, \
   nolog, \
   pass, \
   t:none, \
   setvar:tx.paranoia_level=1"

# Anomaly scoring threshold
# Requests accumulate a score; if score > threshold, block
# Default: 5 (inbound blocking score) / 4 (outbound)
SecAction \
  "id:900110, \
   phase:1, \
   nolog, \
   pass, \
   t:none, \
   setvar:tx.inbound_anomaly_score_threshold=5, \
   setvar:tx.outbound_anomaly_score_threshold=4"

# Allowed HTTP methods
SecAction \
  "id:900200, \
   phase:1, \
   nolog, \
   pass, \
   t:none, \
   setvar:'tx.allowed_methods=GET HEAD POST PUT DELETE PATCH OPTIONS'"

# Allowed content types (tighten for APIs)
SecAction \
  "id:900220, \
   phase:1, \
   nolog, \
   pass, \
   t:none, \
   setvar:'tx.allowed_request_content_type=|application/json| |application/x-www-form-urlencoded| |multipart/form-data|'"

# Max argument count and name/value lengths
SecAction \
  "id:900300, \
   phase:1, \
   nolog, \
   pass, \
   t:none, \
   setvar:tx.max_num_args=255, \
   setvar:tx.arg_name_length=100, \
   setvar:tx.arg_length=400, \
   setvar:tx.total_arg_length=64000, \
   setvar:tx.max_file_size=1048576, \
   setvar:tx.combined_file_sizes=1048576"
```

### Nginx Integration

```nginx
# /etc/nginx/nginx.conf (http block)
modsecurity on;
modsecurity_rules_file /etc/nginx/modsecurity/main.conf;
```

```nginx
# /etc/nginx/modsecurity/main.conf
Include /etc/modsecurity/modsecurity.conf
Include /etc/modsecurity/crs/crs-setup.conf
Include /etc/modsecurity/crs/rules/*.conf
# Custom exclusions (loaded AFTER CRS rules)
Include /etc/modsecurity/custom-exclusions.conf
```

```nginx
# /etc/nginx/sites-enabled/api.conf
server {
    listen 443 ssl http2;
    server_name api.example.com;

    # Enable WAF on this server
    modsecurity on;
    modsecurity_rules_file /etc/nginx/modsecurity/main.conf;

    # Disable WAF for specific locations (e.g., file upload endpoint)
    location /api/upload {
        modsecurity off;
        proxy_pass http://upstream;
    }

    location / {
        proxy_pass http://upstream;
    }
}
```

### Custom ModSecurity Rules

```apacheconf
# /etc/modsecurity/custom-rules.conf

# Block specific malicious User-Agent
SecRule REQUEST_HEADERS:User-Agent "@contains BadBot/1.0" \
    "id:10001, \
     phase:1, \
     deny, \
     status:403, \
     log, \
     msg:'Blocked malicious bot', \
     tag:'custom/bot-block'"

# Block SQL injection pattern in a specific custom parameter
SecRule ARGS:search "@detectSQLi" \
    "id:10002, \
     phase:2, \
     deny, \
     status:400, \
     log, \
     msg:'SQL injection attempt in search parameter', \
     tag:'custom/sqli'"

# Rate limit login endpoint by IP (using IP-based collections)
SecAction \
    "id:10010, \
     phase:1, \
     nolog, \
     pass, \
     initcol:ip=%{REMOTE_ADDR}, \
     setvar:ip.login_count=+1, \
     expirevar:ip.login_count=60"

SecRule IP:LOGIN_COUNT "@gt 10" \
    "id:10011, \
     phase:1, \
     deny, \
     status:429, \
     log, \
     msg:'Login rate limit exceeded', \
     chain"
SecRule REQUEST_URI "@contains /api/login" "t:none"

# Block by IP CIDR range
SecRule REMOTE_ADDR "@ipMatch 185.220.0.0/14" \
    "id:10020, \
     phase:1, \
     deny, \
     status:403, \
     log, \
     msg:'Blocked TOR exit node range'"
```

### Whitelisting False Positives

```apacheconf
# /etc/modsecurity/custom-exclusions.conf

# Remove a specific rule globally (use rule ID from audit log)
SecRuleRemoveById 942100           # Example: SQLi detection false positive

# Remove rule only for a specific path
<LocationMatch "^/api/query">
    SecRuleRemoveById 942100
    SecRuleRemoveById 942110
</LocationMatch>

# Remove by tag (removes all rules with that tag)
SecRuleRemoveByTag "OWASP_CRS/SQL_INJECTION"

# Whitelist a specific argument from rule
SecRuleUpdateTargetById 942100 "!ARGS:filter_query"

# Whitelist entire parameter from all body inspection
SecRuleUpdateTargetByTag "OWASP_CRS" "!ARGS:legit_html_content"
```

---

## Cloudflare WAF

### Manag

Related in Backend & APIs