waf-setup

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

WAF Setup

WAF 部署

Protect web applications with Web Application Firewalls.
使用Web应用防火墙保护Web应用。

When to Use This Skill

何时使用此Skill

Use this skill when:
  • Deploying a public-facing web application that needs attack protection
  • Meeting compliance requirements (PCI-DSS, SOC2) for web application security
  • Blocking OWASP Top 10 attack categories (SQLi, XSS, CSRF, etc.)
  • Protecting APIs from abuse, injection, and rate-based attacks
  • Adding a virtual patching layer while application code is being fixed
在以下情况使用此skill:
  • 部署需要攻击防护的公网Web应用
  • 满足Web应用安全的合规要求(PCI-DSS、SOC2)
  • 阻止OWASP Top 10攻击类别(SQLi、XSS、CSRF等)
  • 保护API免受滥用、注入和基于速率的攻击
  • 在应用程序代码修复期间添加虚拟补丁层

Prerequisites

先决条件

  • Web application behind a load balancer or reverse proxy
  • AWS account for AWS WAF, or Cloudflare account for Cloudflare WAF
  • Nginx with ModSecurity module compiled for self-hosted WAF
  • Access to application logs to tune rules and identify false positives
  • Understanding of HTTP request/response structure
  • 位于负载均衡器或反向代理后面的Web应用
  • 用于AWS WAF的AWS账户,或用于Cloudflare WAF的Cloudflare账户
  • 为自托管WAF编译了ModSecurity模块的Nginx
  • 访问应用日志以调优规则并识别误报
  • 理解HTTP请求/响应结构

AWS WAF

AWS WAF

Create Web ACL with Managed Rules

使用托管规则创建Web ACL

bash
undefined
bash
undefined

Create Web ACL with AWS managed rules

Create Web ACL with AWS managed rules

aws wafv2 create-web-acl
--name production-waf
--scope REGIONAL
--default-action Allow={}
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=production-waf
--rules file://waf-rules.json
undefined
aws wafv2 create-web-acl
--name production-waf
--scope REGIONAL
--default-action Allow={}
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=production-waf
--rules file://waf-rules.json
undefined

AWS WAF Rules Configuration

AWS WAF规则配置

json
[
  {
    "Name": "AWSManagedRulesCommonRuleSet",
    "Priority": 1,
    "Statement": {
      "ManagedRuleGroupStatement": {
        "VendorName": "AWS",
        "Name": "AWSManagedRulesCommonRuleSet",
        "ExcludedRules": []
      }
    },
    "OverrideAction": { "None": {} },
    "VisibilityConfig": {
      "SampledRequestsEnabled": true,
      "CloudWatchMetricsEnabled": true,
      "MetricName": "AWSCommonRules"
    }
  },
  {
    "Name": "AWSManagedRulesSQLiRuleSet",
    "Priority": 2,
    "Statement": {
      "ManagedRuleGroupStatement": {
        "VendorName": "AWS",
        "Name": "AWSManagedRulesSQLiRuleSet"
      }
    },
    "OverrideAction": { "None": {} },
    "VisibilityConfig": {
      "SampledRequestsEnabled": true,
      "CloudWatchMetricsEnabled": true,
      "MetricName": "AWSSQLiRules"
    }
  },
  {
    "Name": "AWSManagedRulesKnownBadInputsRuleSet",
    "Priority": 3,
    "Statement": {
      "ManagedRuleGroupStatement": {
        "VendorName": "AWS",
        "Name": "AWSManagedRulesKnownBadInputsRuleSet"
      }
    },
    "OverrideAction": { "None": {} },
    "VisibilityConfig": {
      "SampledRequestsEnabled": true,
      "CloudWatchMetricsEnabled": true,
      "MetricName": "AWSBadInputRules"
    }
  },
  {
    "Name": "RateLimitRule",
    "Priority": 4,
    "Statement": {
      "RateBasedStatement": {
        "Limit": 2000,
        "AggregateKeyType": "IP"
      }
    },
    "Action": { "Block": {} },
    "VisibilityConfig": {
      "SampledRequestsEnabled": true,
      "CloudWatchMetricsEnabled": true,
      "MetricName": "RateLimit"
    }
  },
  {
    "Name": "GeoBlockRule",
    "Priority": 5,
    "Statement": {
      "GeoMatchStatement": {
        "CountryCodes": ["KP", "IR", "SY"]
      }
    },
    "Action": { "Block": {} },
    "VisibilityConfig": {
      "SampledRequestsEnabled": true,
      "CloudWatchMetricsEnabled": true,
      "MetricName": "GeoBlock"
    }
  },
  {
    "Name": "BlockBadUserAgents",
    "Priority": 6,
    "Statement": {
      "ByteMatchStatement": {
        "SearchString": "sqlmap",
        "FieldToMatch": { "SingleHeader": { "Name": "user-agent" } },
        "TextTransformations": [{ "Priority": 0, "Type": "LOWERCASE" }],
        "PositionalConstraint": "CONTAINS"
      }
    },
    "Action": { "Block": {} },
    "VisibilityConfig": {
      "SampledRequestsEnabled": true,
      "CloudWatchMetricsEnabled": true,
      "MetricName": "BadUserAgent"
    }
  }
]
json
[
  {
    "Name": "AWSManagedRulesCommonRuleSet",
    "Priority": 1,
    "Statement": {
      "ManagedRuleGroupStatement": {
        "VendorName": "AWS",
        "Name": "AWSManagedRulesCommonRuleSet",
        "ExcludedRules": []
      }
    },
    "OverrideAction": { "None": {} },
    "VisibilityConfig": {
      "SampledRequestsEnabled": true,
      "CloudWatchMetricsEnabled": true,
      "MetricName": "AWSCommonRules"
    }
  },
  {
    "Name": "AWSManagedRulesSQLiRuleSet",
    "Priority": 2,
    "Statement": {
      "ManagedRuleGroupStatement": {
        "VendorName": "AWS",
        "Name": "AWSManagedRulesSQLiRuleSet"
      }
    },
    "OverrideAction": { "None": {} },
    "VisibilityConfig": {
      "SampledRequestsEnabled": true,
      "CloudWatchMetricsEnabled": true,
      "MetricName": "AWSSQLiRules"
    }
  },
  {
    "Name": "AWSManagedRulesKnownBadInputsRuleSet",
    "Priority": 3,
    "Statement": {
      "ManagedRuleGroupStatement": {
        "VendorName": "AWS",
        "Name": "AWSManagedRulesKnownBadInputsRuleSet"
      }
    },
    "OverrideAction": { "None": {} },
    "VisibilityConfig": {
      "SampledRequestsEnabled": true,
      "CloudWatchMetricsEnabled": true,
      "MetricName": "AWSBadInputRules"
    }
  },
  {
    "Name": "RateLimitRule",
    "Priority": 4,
    "Statement": {
      "RateBasedStatement": {
        "Limit": 2000,
        "AggregateKeyType": "IP"
      }
    },
    "Action": { "Block": {} },
    "VisibilityConfig": {
      "SampledRequestsEnabled": true,
      "CloudWatchMetricsEnabled": true,
      "MetricName": "RateLimit"
    }
  },
  {
    "Name": "GeoBlockRule",
    "Priority": 5,
    "Statement": {
      "GeoMatchStatement": {
        "CountryCodes": ["KP", "IR", "SY"]
      }
    },
    "Action": { "Block": {} },
    "VisibilityConfig": {
      "SampledRequestsEnabled": true,
      "CloudWatchMetricsEnabled": true,
      "MetricName": "GeoBlock"
    }
  },
  {
    "Name": "BlockBadUserAgents",
    "Priority": 6,
    "Statement": {
      "ByteMatchStatement": {
        "SearchString": "sqlmap",
        "FieldToMatch": { "SingleHeader": { "Name": "user-agent" } },
        "TextTransformations": [{ "Priority": 0, "Type": "LOWERCASE" }],
        "PositionalConstraint": "CONTAINS"
      }
    },
    "Action": { "Block": {} },
    "VisibilityConfig": {
      "SampledRequestsEnabled": true,
      "CloudWatchMetricsEnabled": true,
      "MetricName": "BadUserAgent"
    }
  }
]

Associate WAF with ALB

将WAF与ALB关联

bash
undefined
bash
undefined

Associate with Application Load Balancer

Associate with Application Load Balancer

aws wafv2 associate-web-acl
--web-acl-arn arn:aws:wafv2:us-east-1:123456789:regional/webacl/production-waf/abc123
--resource-arn arn:aws:elasticloadbalancing:us-east-1:123456789:loadbalancer/app/my-alb/abc123
aws wafv2 associate-web-acl
--web-acl-arn arn:aws:wafv2:us-east-1:123456789:regional/webacl/production-waf/abc123
--resource-arn arn:aws:elasticloadbalancing:us-east-1:123456789:loadbalancer/app/my-alb/abc123

Associate with API Gateway

Associate with API Gateway

aws wafv2 associate-web-acl
--web-acl-arn arn:aws:wafv2:us-east-1:123456789:regional/webacl/production-waf/abc123
--resource-arn arn:aws:apigateway:us-east-1::/restapis/abc123/stages/prod
undefined
aws wafv2 associate-web-acl
--web-acl-arn arn:aws:wafv2:us-east-1:123456789:regional/webacl/production-waf/abc123
--resource-arn arn:aws:apigateway:us-east-1::/restapis/abc123/stages/prod
undefined

AWS WAF Terraform

AWS WAF Terraform

hcl
resource "aws_wafv2_web_acl" "main" {
  name        = "production-waf"
  scope       = "REGIONAL"
  description = "Production WAF with OWASP protections"

  default_action {
    allow {}
  }

  rule {
    name     = "AWSManagedRulesCommonRuleSet"
    priority = 1

    override_action { none {} }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesCommonRuleSet"
        vendor_name = "AWS"

        rule_action_override {
          name = "SizeRestrictions_BODY"
          action_to_use { count {} }
        }
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "AWSCommonRules"
      sampled_requests_enabled   = true
    }
  }

  rule {
    name     = "RateLimit"
    priority = 10

    action { block {} }

    statement {
      rate_based_statement {
        limit              = 2000
        aggregate_key_type = "IP"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "RateLimit"
      sampled_requests_enabled   = true
    }
  }

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = "production-waf"
    sampled_requests_enabled   = true
  }
}

resource "aws_wafv2_web_acl_association" "alb" {
  resource_arn = aws_lb.main.arn
  web_acl_arn  = aws_wafv2_web_acl.main.arn
}
hcl
resource "aws_wafv2_web_acl" "main" {
  name        = "production-waf"
  scope       = "REGIONAL"
  description = "Production WAF with OWASP protections"

  default_action {
    allow {}
  }

  rule {
    name     = "AWSManagedRulesCommonRuleSet"
    priority = 1

    override_action { none {} }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesCommonRuleSet"
        vendor_name = "AWS"

        rule_action_override {
          name = "SizeRestrictions_BODY"
          action_to_use { count {} }
        }
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "AWSCommonRules"
      sampled_requests_enabled   = true
    }
  }

  rule {
    name     = "RateLimit"
    priority = 10

    action { block {} }

    statement {
      rate_based_statement {
        limit              = 2000
        aggregate_key_type = "IP"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "RateLimit"
      sampled_requests_enabled   = true
    }
  }

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = "production-waf"
    sampled_requests_enabled   = true
  }
}

resource "aws_wafv2_web_acl_association" "alb" {
  resource_arn = aws_lb.main.arn
  web_acl_arn  = aws_wafv2_web_acl.main.arn
}

Cloudflare WAF

Cloudflare WAF

API Configuration

API配置

bash
undefined
bash
undefined

List available WAF rulesets

List available WAF rulesets

curl -s "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/rulesets"
-H "Authorization: Bearer ${CF_TOKEN}" | jq '.result[] | {id, name, phase}'
curl -s "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/rulesets"
-H "Authorization: Bearer ${CF_TOKEN}" | jq '.result[] | {id, name, phase}'

Create a custom WAF rule

Create a custom WAF rule

curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/rulesets"
-H "Authorization: Bearer ${CF_TOKEN}"
-H "Content-Type: application/json"
-d '{ "name": "Custom WAF Rules", "kind": "zone", "phase": "http_request_firewall_custom", "rules": [ { "action": "block", "expression": "(http.request.uri.query contains "union select" or http.request.uri.query contains "1=1")", "description": "Block SQL injection patterns in query string" }, { "action": "block", "expression": "(http.request.uri.path contains "..%2f" or http.request.uri.path contains "..%5c")", "description": "Block path traversal attempts" }, { "action": "challenge", "expression": "(cf.threat_score gt 30)", "description": "Challenge high threat score visitors" }, { "action": "block", "expression": "(http.request.headers["user-agent"] contains "sqlmap" or http.request.headers["user-agent"] contains "nikto")", "description": "Block known attack tools" } ] }'
curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/rulesets"
-H "Authorization: Bearer ${CF_TOKEN}"
-H "Content-Type: application/json"
-d '{ "name": "Custom WAF Rules", "kind": "zone", "phase": "http_request_firewall_custom", "rules": [ { "action": "block", "expression": "(http.request.uri.query contains "union select" or http.request.uri.query contains "1=1")", "description": "Block SQL injection patterns in query string" }, { "action": "block", "expression": "(http.request.uri.path contains "..%2f" or http.request.uri.path contains "..%5c")", "description": "Block path traversal attempts" }, { "action": "challenge", "expression": "(cf.threat_score gt 30)", "description": "Challenge high threat score visitors" }, { "action": "block", "expression": "(http.request.headers["user-agent"] contains "sqlmap" or http.request.headers["user-agent"] contains "nikto")", "description": "Block known attack tools" } ] }'

Configure rate limiting

Configure rate limiting

curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/rulesets"
-H "Authorization: Bearer ${CF_TOKEN}"
-H "Content-Type: application/json"
-d '{ "name": "Rate Limiting", "kind": "zone", "phase": "http_ratelimit", "rules": [ { "action": "block", "ratelimit": { "characteristics": ["ip.src"], "period": 60, "requests_per_period": 100, "mitigation_timeout": 600 }, "expression": "(http.request.uri.path matches "^/api/")", "description": "Rate limit API endpoints" } ] }'
undefined
curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/rulesets"
-H "Authorization: Bearer ${CF_TOKEN}"
-H "Content-Type: application/json"
-d '{ "name": "Rate Limiting", "kind": "zone", "phase": "http_ratelimit", "rules": [ { "action": "block", "ratelimit": { "characteristics": ["ip.src"], "period": 60, "requests_per_period": 100, "mitigation_timeout": 600 }, "expression": "(http.request.uri.path matches "^/api/")", "description": "Rate limit API endpoints" } ] }'
undefined

Cloudflare Terraform

Cloudflare Terraform

hcl
resource "cloudflare_ruleset" "waf_custom" {
  zone_id = var.zone_id
  name    = "Custom WAF Rules"
  kind    = "zone"
  phase   = "http_request_firewall_custom"

  rules {
    action      = "block"
    expression  = "(http.request.uri.query contains \"union select\")"
    description = "Block SQL injection in query string"
  }

  rules {
    action      = "managed_challenge"
    expression  = "(cf.threat_score gt 30)"
    description = "Challenge suspicious visitors"
  }
}
hcl
resource "cloudflare_ruleset" "waf_custom" {
  zone_id = var.zone_id
  name    = "Custom WAF Rules"
  kind    = "zone"
  phase   = "http_request_firewall_custom"

  rules {
    action      = "block"
    expression  = "(http.request.uri.query contains \"union select\")"
    description = "Block SQL injection in query string"
  }

  rules {
    action      = "managed_challenge"
    expression  = "(cf.threat_score gt 30)"
    description = "Challenge suspicious visitors"
  }
}

ModSecurity with Nginx

ModSecurity与Nginx

Installation

安装

bash
undefined
bash
undefined

Install ModSecurity for Nginx (Ubuntu)

Install ModSecurity for Nginx (Ubuntu)

apt install -y libmodsecurity3 libmodsecurity-dev nginx libnginx-mod-http-modsecurity
apt install -y libmodsecurity3 libmodsecurity-dev nginx libnginx-mod-http-modsecurity

Or compile from source

Or compile from source

git clone https://github.com/SpiderLabs/ModSecurity /opt/modsecurity cd /opt/modsecurity git submodule init && git submodule update ./build.sh && ./configure && make && make install
undefined
git clone https://github.com/SpiderLabs/ModSecurity /opt/modsecurity cd /opt/modsecurity git submodule init && git submodule update ./build.sh && ./configure && make && make install
undefined

Nginx Configuration

Nginx配置

nginx
undefined
nginx
undefined

/etc/nginx/nginx.conf

/etc/nginx/nginx.conf

load_module modules/ngx_http_modsecurity_module.so;
http { modsecurity on; modsecurity_rules_file /etc/nginx/modsec/main.conf;
server {
    listen 443 ssl http2;
    server_name example.com;

    # ModSecurity can also be enabled per-location
    location /api/ {
        modsecurity on;
        modsecurity_rules_file /etc/nginx/modsec/api-rules.conf;
        proxy_pass http://backend;
    }
}
}
undefined
load_module modules/ngx_http_modsecurity_module.so;
http { modsecurity on; modsecurity_rules_file /etc/nginx/modsec/main.conf;
server {
    listen 443 ssl http2;
    server_name example.com;

    # ModSecurity can also be enabled per-location
    location /api/ {
        modsecurity on;
        modsecurity_rules_file /etc/nginx/modsec/api-rules.conf;
        proxy_pass http://backend;
    }
}
}
undefined

ModSecurity Main Configuration

ModSecurity主配置

bash
undefined
bash
undefined

/etc/nginx/modsec/main.conf

/etc/nginx/modsec/main.conf

Include /etc/nginx/modsec/modsecurity.conf
Include /etc/nginx/modsec/modsecurity.conf

Set to DetectionOnly first, switch to On after tuning

Set to DetectionOnly first, switch to On after tuning

SecRuleEngine On
SecRuleEngine On

Request body handling

Request body handling

SecRequestBodyAccess On SecRequestBodyLimit 13107200 SecRequestBodyNoFilesLimit 131072
SecRequestBodyAccess On SecRequestBodyLimit 13107200 SecRequestBodyNoFilesLimit 131072

Response body handling

Response body handling

SecResponseBodyAccess On SecResponseBodyMimeType text/plain text/html text/xml application/json
SecResponseBodyAccess On SecResponseBodyMimeType text/plain text/html text/xml application/json

Logging

Logging

SecAuditEngine RelevantOnly SecAuditLogRelevantStatus "^(?:5|4(?!04))" SecAuditLogParts ABIJDEFHZ SecAuditLogType Serial SecAuditLog /var/log/modsec/modsec_audit.log
SecAuditEngine RelevantOnly SecAuditLogRelevantStatus "^(?:5|4(?!04))" SecAuditLogParts ABIJDEFHZ SecAuditLogType Serial SecAuditLog /var/log/modsec/modsec_audit.log

Include OWASP Core Rule Set

Include OWASP Core Rule Set

Include /etc/nginx/modsec/crs/crs-setup.conf Include /etc/nginx/modsec/crs/rules/*.conf
undefined
Include /etc/nginx/modsec/crs/crs-setup.conf Include /etc/nginx/modsec/crs/rules/*.conf
undefined

OWASP Core Rule Set Setup

OWASP核心规则集设置

bash
undefined
bash
undefined

Download and install OWASP CRS

Download and install OWASP CRS

cd /etc/nginx/modsec git clone https://github.com/coreruleset/coreruleset crs cp crs/crs-setup.conf.example crs/crs-setup.conf
cd /etc/nginx/modsec git clone https://github.com/coreruleset/coreruleset crs cp crs/crs-setup.conf.example crs/crs-setup.conf

Customize CRS settings

Customize CRS settings

cat >> crs/crs-setup.conf << 'EOF'
cat >> crs/crs-setup.conf << 'EOF'

Set paranoia level (1-4, higher = more strict)

Set paranoia level (1-4, higher = more strict)

SecAction "id:900000, phase:1, pass, t:none, nolog, setvar:tx.paranoia_level=2"
SecAction "id:900000, phase:1, pass, t:none, nolog, setvar:tx.paranoia_level=2"

Set anomaly score thresholds

Set anomaly score thresholds

SecAction "id:900110, phase:1, pass, t:none, nolog,
setvar:tx.inbound_anomaly_score_threshold=5,
setvar:tx.outbound_anomaly_score_threshold=4"
SecAction "id:900110, phase:1, pass, t:none, nolog,
setvar:tx.inbound_anomaly_score_threshold=5,
setvar:tx.outbound_anomaly_score_threshold=4"

Exclude known false positives

Exclude known false positives

SecRule REQUEST_URI "@beginsWith /api/upload"
"id:1001,phase:1,pass,nolog,ctl:ruleRemoveById=920420" EOF
SecRule REQUEST_URI "@beginsWith /api/upload"
"id:1001,phase:1,pass,nolog,ctl:ruleRemoveById=920420" EOF

Create rule exclusions file

Create rule exclusions file

cat > /etc/nginx/modsec/crs/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf << 'EOF'
cat > /etc/nginx/modsec/crs/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf << 'EOF'

Exclude rules that cause false positives on specific paths

Exclude rules that cause false positives on specific paths

SecRule REQUEST_URI "@beginsWith /api/webhook"
"id:1000001,phase:1,pass,nolog,ctl:ruleRemoveTargetById=942100;ARGS:payload"
SecRule REQUEST_URI "@beginsWith /api/webhook"
"id:1000001,phase:1,pass,nolog,ctl:ruleRemoveTargetById=942100;ARGS:payload"

Exclude rules for specific parameters

Exclude rules for specific parameters

SecRule ARGS_NAMES "^content$"
"id:1000002,phase:1,pass,nolog,ctl:ruleRemoveTargetById=941100;ARGS:content" EOF
undefined
SecRule ARGS_NAMES "^content$"
"id:1000002,phase:1,pass,nolog,ctl:ruleRemoveTargetById=941100;ARGS:content" EOF
undefined

Custom ModSecurity Rules

自定义ModSecurity规则

bash
undefined
bash
undefined

/etc/nginx/modsec/custom-rules.conf

/etc/nginx/modsec/custom-rules.conf

Block requests with known attack tool user agents

Block requests with known attack tool user agents

SecRule REQUEST_HEADERS:User-Agent "@pm sqlmap nikto nmap masscan dirbuster"
"id:10001,phase:1,deny,status:403,log,msg:'Blocked attack tool'"
SecRule REQUEST_HEADERS:User-Agent "@pm sqlmap nikto nmap masscan dirbuster"
"id:10001,phase:1,deny,status:403,log,msg:'Blocked attack tool'"

Block requests to sensitive paths

Block requests to sensitive paths

SecRule REQUEST_URI "@rx /(.git|.env|.svn|wp-admin|phpmyadmin|adminer)"
"id:10002,phase:1,deny,status:404,log,msg:'Blocked sensitive path access'"
SecRule REQUEST_URI "@rx /(.git|.env|.svn|wp-admin|phpmyadmin|adminer)"
"id:10002,phase:1,deny,status:404,log,msg:'Blocked sensitive path access'"

Rate limit by IP (10 requests/second)

Rate limit by IP (10 requests/second)

SecRule IP:REQUEST_RATE "@gt 10"
"id:10003,phase:1,deny,status:429,log,msg:'Rate limit exceeded',
setvar:IP.request_rate=+1,expirevar:IP.request_rate=1"
SecRule IP:REQUEST_RATE "@gt 10"
"id:10003,phase:1,deny,status:429,log,msg:'Rate limit exceeded',
setvar:IP.request_rate=+1,expirevar:IP.request_rate=1"

Block oversized cookies (potential overflow attack)

Block oversized cookies (potential overflow attack)

SecRule REQUEST_HEADERS:Cookie "@gt 4096"
"id:10004,phase:1,deny,status:400,log,msg:'Oversized cookie header'"
SecRule REQUEST_HEADERS:Cookie "@gt 4096"
"id:10004,phase:1,deny,status:400,log,msg:'Oversized cookie header'"

Virtual patch: block specific CVE exploit pattern

Virtual patch: block specific CVE exploit pattern

SecRule ARGS:filename "@contains ../../"
"id:10005,phase:2,deny,status:403,log,msg:'Path traversal blocked (virtual patch CVE-XXXX-XXXX)'"
SecRule ARGS:filename "@contains ../../"
"id:10005,phase:2,deny,status:403,log,msg:'Path traversal blocked (virtual patch CVE-XXXX-XXXX)'"

Require Content-Type on POST requests

Require Content-Type on POST requests

SecRule REQUEST_METHOD "@streq POST"
"id:10006,phase:1,chain,deny,status:400,log,msg:'POST without Content-Type'" SecRule &REQUEST_HEADERS:Content-Type "@eq 0" ""
undefined
SecRule REQUEST_METHOD "@streq POST"
"id:10006,phase:1,chain,deny,status:400,log,msg:'POST without Content-Type'" SecRule &REQUEST_HEADERS:Content-Type "@eq 0" ""
undefined

WAF Tuning Workflow

WAF调优工作流

bash
#!/bin/bash
bash
#!/bin/bash

waf-tune.sh - Analyze WAF logs for false positives

waf-tune.sh - Analyze WAF logs for false positives

AUDIT_LOG="/var/log/modsec/modsec_audit.log" TIMEFRAME="24h"
echo "=== WAF Tuning Report ===" echo "Analyzing last ${TIMEFRAME} of audit logs" echo ""
AUDIT_LOG="/var/log/modsec/modsec_audit.log" TIMEFRAME="24h"
echo "=== WAF Tuning Report ===" echo "Analyzing last ${TIMEFRAME} of audit logs" echo ""

Top blocked rules

Top blocked rules

echo "--- Top 10 triggered rules ---" grep -oP 'id "\K[0-9]+' "$AUDIT_LOG" | sort | uniq -c | sort -rn | head -10
echo "" echo "--- Top blocked URIs ---" grep -oP 'REQUEST_URI: \K[^\s]+' "$AUDIT_LOG" | sort | uniq -c | sort -rn | head -10
echo "" echo "--- Top blocked IPs ---" grep -oP 'client \K[0-9.]+' "$AUDIT_LOG" | sort | uniq -c | sort -rn | head -10
echo "" echo "--- False positive candidates (high-frequency blocks on common paths) ---" grep -oP 'id "\K[0-9]+' "$AUDIT_LOG" | sort | uniq -c | sort -rn |
while read count rule_id; do if [ "$count" -gt 100 ]; then echo " Rule $rule_id triggered $count times - review for false positive" fi done
undefined
echo "--- Top 10 triggered rules ---" grep -oP 'id "\K[0-9]+' "$AUDIT_LOG" | sort | uniq -c | sort -rn | head -10
echo "" echo "--- Top blocked URIs ---" grep -oP 'REQUEST_URI: \K[^\s]+' "$AUDIT_LOG" | sort | uniq -c | sort -rn | head -10
echo "" echo "--- Top blocked IPs ---" grep -oP 'client \K[0-9.]+' "$AUDIT_LOG" | sort | uniq -c | sort -rn | head -10
echo "" echo "--- False positive candidates (high-frequency blocks on common paths) ---" grep -oP 'id "\K[0-9]+' "$AUDIT_LOG" | sort | uniq -c | sort -rn |
while read count rule_id; do if [ "$count" -gt 100 ]; then echo " Rule $rule_id triggered $count times - review for false positive" fi done
undefined

Troubleshooting

故障排除

ProblemCauseSolution
Legitimate requests blockedFalse positives from CRS rulesSet
SecRuleEngine DetectionOnly
first; review audit log; add exclusions
WAF not blocking attacksRules in detection-only modeSwitch
SecRuleEngine On
after tuning period
High latency with WAF enabledResponse body inspection overheadDisable
SecResponseBodyAccess
if not needed; reduce
paranoia_level
AWS WAF rules not matchingRule priority order wrongLower priority number = evaluated first; reorder rules
ModSecurity crashes nginxMemory exhaustion on large requestsIncrease
SecRequestBodyLimit
; adjust
SecPcreMatchLimit
Cloudflare WAF blocks API callsExpression too broadNarrow expression with path or method conditions
CRS update breaks applicationNew rules trigger on existing trafficPin CRS version; test updates in staging first
问题原因解决方案
合法请求被阻止CRS规则误报先设置
SecRuleEngine DetectionOnly
;查看审计日志;添加排除规则
WAF未阻止攻击规则处于仅检测模式调优期后切换
SecRuleEngine On
启用WAF后延迟高响应体检查开销如非必要,禁用
SecResponseBodyAccess
;降低
paranoia_level
AWS WAF规则不匹配规则优先级顺序错误较低优先级数字 = 先评估;重排规则
ModSecurity导致Nginx崩溃大请求导致内存耗尽增加
SecRequestBodyLimit
;调整
SecPcreMatchLimit
Cloudflare WAF阻止API调用表达式过于宽泛使用路径或方法条件缩小表达式
CRS更新破坏应用新规则触发现有流量固定CRS版本;先在staging环境测试更新

Best Practices

最佳实践

  • Start in detection/log mode, switch to blocking after tuning
  • Tune rules for at least 1-2 weeks before enforcement
  • Monitor blocked requests daily during tuning phase
  • Update managed rule sets and CRS regularly
  • Create custom rules for application-specific attack patterns
  • Use virtual patching to protect against known CVEs while code is being fixed
  • Set appropriate rate limits per endpoint
  • Maintain exclusion rules documentation with justifications
  • Test WAF rules with known attack payloads before deploying
  • Keep audit logs for at least 90 days for forensic analysis
  • 从检测/日志模式开始,调优后再切换为阻断
  • 强制实施前至少调优规则1-2周
  • 调优期间每天监控被阻止的请求
  • 定期更新托管规则集和CRS
  • 为应用特定的攻击模式创建自定义规则
  • 使用虚拟补丁在代码修复期间防范已知CVE
  • 为每个端点设置适当的速率限制
  • 保留排除规则文档并注明原因
  • 部署前使用已知攻击payload测试WAF规则
  • 保留审计日志至少90天,用于取证分析

Related Skills

相关Skill

  • dast-scanning - Web security testing
  • ssl-tls-management - HTTPS configuration
  • firewall-config - Network-level firewalling
  • dast-scanning - Web安全测试
  • ssl-tls-management - HTTPS配置
  • firewall-config - 网络层防火墙