关于 waf-setup
waf-setup 是用于配置 Web 应用防火墙的安全技能,涵盖 AWS WAF、Cloudflare WAF 和搭配 ModSecurity 的 Nginx。它介绍规则部署、调优、故障排查及 Web 应用和 API 的防护方法。
主要功能
- 01配置 AWS WAF 与规则
- 02配置 Cloudflare WAF
- 03设置 Nginx 与 ModSecurity
- 04集成 OWASP CRS
- 05调优规则并分析误报
- 06速率限制与虚拟补丁
适用场景
- 01为公开 Web 应用部署防护
- 02降低 SQLi、XSS 等攻击风险
- 03保护 API 免受滥用与注入
- 04代码修复期间实施虚拟补丁
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ bagelhole/ devops-security-agent-skills --skill waf-setup安装后在 Claude Code 中输入/waf-setup确认已加载。
附带文件references/waf-rules.md
详细介绍
WAF 设置
使用 Web 应用防火墙保护 Web 应用。
适用场景
在以下情况下使用此技能:
- 部署需要防护攻击的面向公众的 Web 应用
- 满足 Web 应用安全方面的合规要求(PCI-DSS、SOC2)
- 阻止 OWASP Top 10 攻击类别(SQLi、XSS、CSRF 等)
- 保护 API 免受滥用、注入和基于速率的攻击
- 在修复应用代码期间添加虚拟补丁层
前提条件
- Web 应用部署在负载均衡器或反向代理之后
- 使用 AWS WAF 需要 AWS 账户;使用 Cloudflare WAF 需要 Cloudflare 账户
- 使用可自托管的 WAF 需要编译了 ModSecurity 模块的 Nginx
- 能够访问应用日志,以调整规则并识别误报
- 了解 HTTP 请求/响应结构
AWS WAF
创建包含托管规则的 Web ACL
# 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
AWS WAF 规则配置
[
{
"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"
}
}
]
将 WAF 与 ALB 关联
# 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
# 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
AWS WAF Terraform 配置
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
API 配置
# 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}'
# 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"
}
]
}'
# 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"
}
]
}'
Cloudflare Terraform 配置
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"
}
}
使用 Nginx 配置 ModSecurity
安装
# Install ModSecurity for Nginx (Ubuntu)
apt install -y libmodsecurity3 libmodsecurity-dev nginx libnginx-mod-http-modsecurity
# 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
Nginx 配置
# /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;
}
}
}
ModSecurity 主配置
# /etc/nginx/modsec/main.conf
Include /etc/nginx/modsec/modsecurity.conf
# Set to DetectionOnly first, switch to On after tuning
SecRuleEngine On
# Request body handling
SecRequestBodyAccess On
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
# Response body handling
SecResponseBodyAccess On
SecResponseBodyMimeType text/plain text/html text/xml application/json
# Logging
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABIJDEFHZ
SecAuditLogType Serial
SecAuditLog /var/log/modsec/modsec_audit.log
# Include OWASP Core Rule Set
Include /etc/nginx/modsec/crs/crs-setup.conf
Include /etc/nginx/modsec/crs/rules/*.conf
OWASP 核心规则集设置
# 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
# Customize CRS settings
cat >> crs/crs-setup.conf << 'EOF'
# Set paranoia level (1-4, higher = more strict)
SecAction "id:900000, phase:1, pass, t:none, nolog, setvar:tx.paranoia_level=2"
# 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"
# Exclude known false positives
SecRule REQUEST_URI "@beginsWith /api/upload" \
"id:1001,phase:1,pass,nolog,ctl:ruleRemoveById=920420"
EOF
# Create rule exclusions file
cat > /etc/nginx/modsec/crs/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf << 'EOF'
# 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"
# Exclude rules for specific parameters
SecRule ARGS_NAMES "^content$" \
"id:1000002,phase:1,pass,nolog,ctl:ruleRemoveTargetById=941100;ARGS:content"
EOF
自定义 ModSecurity 规则
# /etc/nginx/modsec/custom-rules.conf
# 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'"
# 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'"
# 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"
# Block oversized cookies (potential overflow attack)
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
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
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" ""
WAF 调优工作流
#!/bin/bash
# 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 ""
# 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
故障排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 合法请求被阻止 | CRS 规则产生误报 | 先设置 SecRuleEngine DetectionOnly;检查审计日志;添加排除项 |
| WAF 未阻止攻击 | 规则处于仅检测模式 | 调优期结束后切换到 SecRuleEngine On |
| 启用 WAF 后延迟较高 | 检查响应正文带来的开销 | 如果不需要,禁用 SecResponseBodyAccess;降低 paranoia_level |
| AWS WAF 规则未匹配 | 规则优先级顺序错误 | 优先级数字越小,越先评估;调整规则顺序 |
| ModSecurity 导致 nginx 崩溃 | 大型请求导致内存耗尽 | 增大 SecRequestBodyLimit;调整 SecPcreMatchLimit |
| Cloudflare WAF 阻止 API 调用 | 表达式范围过宽 | 添加路径或方法条件以缩小表达式范围 |
| CRS 更新导致应用故障 | 新规则匹配现有流量 | 固定 CRS 版本;先在预发布环境测试更新 |
最佳实践
- 从检测/日志模式开始,调优后再切换到阻止模式
- 强制执行前至少调优规则 1-2 周
- 在调优阶段每天监控被阻止的请求
- 定期更新托管规则集和 CRS
- 针对应用特有的攻击模式创建自定义规则
- 在修复代码期间,使用虚拟补丁防护已知 CVE
- 为每个端点设置适当的速率限制
- 保留排除规则文档并说明理由
- 部署前使用已知攻击载荷测试 WAF 规则
- 至少保留审计日志 90 天,以便进行取证分析
相关技能
- dast-scanning - Web 安全测试
- ssl-tls-management - HTTPS 配置
- firewall-config - 网络层防火墙配置
评论
支持 Markdown