Cloudflare Business 年费 $2,400/域名,Imperva WAF 年费 $5,000+。对于需要自建WAF的企业,ModSecurity + OWASP CRS 是完全免费的方案,防护能力不亚于商业WAF。本文讲解如何从零搭建生产级WAF。
为什么选ModSecurity
| 功能 | Cloudflare Pro | Imperva WAF | ModSecurity + CRS |
|---|---|---|---|
| SQL注入防护 | 优秀 | 优秀 | 优秀 |
| XSS防护 | 优秀 | 优秀 | 优秀 |
| Bot防护 | 优秀 | 优秀 | 基础 |
| DDoS防护 | 优秀 | 优秀 | 需配合 |
| 自定义规则 | 有限 | 完整 | 完整 |
| 日志分析 | 仪表盘 | 仪表盘 | 自建 |
| SSL卸载 | 内置 | 内置 | Nginx/Apache |
| 价格 | $20/月/域名 | $5,000+/年 | 免费 |
ModSecurity的核心优势是规则完全可控——你可以针对业务逻辑写精确的WAF规则,这是商业WAF做不到的。
架构方案
方案A: Nginx + ModSecurity(推荐)
[Client] → [Nginx+ModSecurity] → [Backend App]
方案B: Apache + ModSecurity
[Client] → [Apache+mod_security] → [Backend App]
方案C: 独立WAF网关
[Client] → [HAProxy] → [ModSecurity] → [Backend App]
安装Nginx + ModSecurity
方式一:编译安装(推荐,功能完整)
# 安装依赖
apt update && apt install -y \
gcc make build-essential \
libpcre3-dev libssl-dev zlib1g-dev \
libxml2-dev libxslt1-dev libgd-dev \
libgeoip-dev liblmdb-dev libyajl-dev \
libcurl4-openssl-dev libpcre++-dev \
git automake libtool autoconf \
pkgconf libpcre2-dev
# 1. 克隆ModSecurity源码
cd /opt
git clone --depth 1 -b v3/master https://github.com/owasp-modsecurity/ModSecurity.git
cd ModSecurity
git submodule init
git submodule update
# 编译ModSecurity
./build.sh
./configure --with-pcre2
make -j$(nproc)
make install
# 2. 克隆Nginx ModSecurity连接器
cd /opt
git clone --depth 1 https://github.com/owasp-modsecurity/ModSecurity-nginx.git
# 3. 编译Nginx(添加ModSecurity模块)
NGINX_VERSION=1.26.1
wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz
tar xzf nginx-${NGINX_VERSION}.tar.gz
cd nginx-${NGINX_VERSION}
./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib64/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_gzip_static_module \
--with-http_secure_link_module \
--add-dynamic-module=/opt/ModSecurity-nginx
make -j$(nproc)
make install
方式二:apt安装(Ubuntu)
apt install -y libmodsecurity3 libmodsecurity3-nginx nginx
方式三:Docker
docker pull owasp/modsecurity-crs:nginx
docker run -d --name waf \
-p 80:80 -p 443:443 \
-e BACKEND=http://192.168.1.100:8080 \
-e PARANOIA=1 \
-v /var/log/modsecurity:/var/log/modsecurity \
owasp/modsecurity-crs:nginx
ModSecurity核心配置
/etc/nginx/modsecurity/modsecurity.conf
# 启用ModSecurity
SecRuleEngine On
# 请求体处理
SecRequestBodyAccess On
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
SecRequestBodyLimitAction Reject
# 响应体处理
SecResponseBodyAccess On
SecResponseBodyMimeType text/plain text/html text/xml application/json
SecResponseBodyLimit 524288
SecResponseBodyLimitAction ProcessPartial
# 临时文件路径
SecTmpDir /tmp/modsecurity/tmp
SecDataDir /tmp/modsecurity/data
SecUploadDir /tmp/modsecurity/upload
# 日志配置
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABIJDEFHZ
SecAuditLogType Serial
SecAuditLog /var/log/modsecurity/modsec_audit.log
# 调试日志(生产环境关闭)
SecDebugLog /var/log/modsecurity/modsec_debug.log
SecDebugLogLevel 0
# 动作默认值
SecDefaultAction "phase:1,deny,log,status:403"
# PCRE调优
SecPcreMatchLimit 100000
SecPcreMatchLimitRecursion 100000
# Unicode映射
SecUnicodeMapFile /etc/nginx/modsecurity/unicode.mapping 20127
# 隐藏服务器标识
SecServerEngine On
SecServerTag "Server"
/etc/nginx/modsecurity/crs-setup.conf
# OWASP CRS配置
# 偏执级别(1-4,越高越严格,误报越多)
SecAction "id:900000,phase:1,nolog,pass,t:none,setvar:tx.paranoia_level=1"
# 执行异常评分(累计攻击分数触发阻断)
SecAction "id:900110,phase:1,nolog,pass,t:none,setvar:tx.blocking_paranoia_level=1"
# 检测SQL注入的阈值
SecAction "id:900200,phase:1,nolog,pass,t:none,setvar:'tx.sql_injection_score_threshold=5'"
# 检测XSS的阈值
SecAction "id:900210,phase:1,nolog,pass,t:none,setvar:'tx.xss_score_threshold=5'"
# 检测RFI/LFI的阈值
SecAction "id:900220,phase:1,nolog,pass,t:none,setvar:'tx.rfi_score_threshold=5'"
SecAction "id:900230,phase:1,nolog,pass,t:none,setvar:'tx.lfi_score_threshold=5'"
# 允许的HTTP方法
SecAction "id:900240,phase:1,nolog,pass,t:none,setvar:'tx.allowed_methods=GET HEAD POST OPTIONS PUT PATCH DELETE'"
# 允许的Content-Type
SecAction "id:900260,phase:1,nolog,pass,t:none,setvar:'tx.allowed_request_content_type=|application/x-www-form-urlencoded| |multipart/form-data| |multipart/related| |text/xml| |application/xml| |application/soap+xml| |application/json| |application/cloudevents+json| |application/cloudevents-batch+json|'"
# 允许的文件扩展名(白名单)
SecAction "id:900270,phase:1,nolog,pass,t:none,setvar:'tx.allowed_request_content_type_charset=|utf-8| |iso-8859-1| |iso-8859-15| |windows-1252|'"
# 地理位置封禁(可选)
# SecAction "id:900600,phase:1,nolog,pass,t:none,setvar:'tx.high_risk_country_codes='"
# 禁用某些规则(针对业务误报处理)
# SecRuleRemoveById 941100
# SecRuleRemoveById 942100
Nginx配置集成ModSecurity
# /etc/nginx/nginx.conf
load_module modules/ngx_http_modsecurity_module.so;
http {
modsecurity on;
modsecurity_rules_file /etc/nginx/modsecurity/modsecurity.conf;
upstream backend {
server 192.168.1.100:8080;
}
server {
listen 80;
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# 针对特定路径调整规则
location /api/ {
modsecurity_rules '
SecRuleEngine On
SecRuleRemoveById 920170 # 允许无Accept头
SecRuleRemoveById 942100 # 放宽SQL注入检测
';
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 静态资源不走WAF
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
modsecurity off;
proxy_pass http://backend;
}
}
}
自定义WAF规则
/etc/nginx/modsecurity/custom-rules.conf
# === 业务层防护规则 ===
# 封禁已知恶意IP(从威胁情报导入)
SecRule REMOTE_ADDR "@ipMatchFromFile /etc/nginx/modsecurity/bad_ips.txt" \
"id:100001,phase:1,drop,log,msg:'Blocked malicious IP'"
# 防爬虫:限制请求频率
SecAction "id:100010,phase:1,pass,nolog,initcol:ip=%{REMOTE_ADDR}"
SecRule IP:REQUEST_COUNT "@gt 100" \
"id:100011,phase:1,drop,log,msg:'Rate limit exceeded: %{REMOTE_ADDR}'"
SecRule REQUEST_URI ".*" \
"id:100012,phase:5,pass,nolog,setvar:ip.request_count=+1"
# 防护路径遍历
SecRule REQUEST_URI "@rx /\.\./" \
"id:100020,phase:1,drop,log,msg:'Path traversal attempt'"
# 防护命令注入
SecRule ARGS|ARGS_NAMES|REQUEST_HEADERS "@rx (?:;|\|`|&&|\$\(|\$\{)" \
"id:100030,phase:2,drop,log,msg:'Command injection attempt'"
# 防护SSRF
SecRule ARGS "@rx (?:file|gopher|dict|php|data):" \
"id:100040,phase:2,drop,log,msg:'SSRF attempt detected'"
# 防护反序列化攻击
SecRule ARGS|REQUEST_BODY "@rx (?:O:|a:|s:)\d+:" \
"id:100050,phase:2,drop,log,msg:'PHP deserialization attempt'"
# 防护JWT篡改
SecRule REQUEST_HEADERS:Authorization "@rx ^Bearer\s+[A-Za-z0-9_-]+\.eyJ" \
"id:100060,phase:1,pass,log,setvar:'tx.jwt_token=%{MATCHED_VAR}'"
# 防护文件上传(只允许指定类型)
SecRule FILES_TMPNAMES "@rx \.(?:php|phtml|php3|php4|php5|phps|asp|aspx|jsp|cgi|sh|bat|exe|dll)$" \
"id:100070,phase:2,drop,log,msg:'Malicious file upload blocked'"
# 白名单:排除内部API调用
SecRule REMOTE_ADDR "@ipMatch 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" \
"id:100080,phase:1,pass,nolog,ctl:ruleEngine=Off"
恶意IP列表文件
# /etc/nginx/modsecurity/bad_ips.txt
# 格式:每行一个IP或CIDR
203.0.113.0/24
198.51.100.0/24
192.0.2.1
# 从威胁情报源自动更新
日志分析
实时告警脚本
cat > /opt/waf-alert.sh << 'SCRIPT'
#!/bin/bash
tail -f /var/log/modsecurity/modsec_audit.log | while read line; do
if echo "$line" | grep -q "\[id \"[0-9]"; then
RULE_ID=$(echo "$line" | grep -oP '\[id "\K[0-9]+')
SRC_IP=$(echo "$line" | grep -oP 'client "\K[^"]+')
URI=$(echo "$line" | grep -oP 'uri "\K[^"]+')
# 发送告警到企业微信
curl -s -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY" \
-H 'Content-Type: application/json' \
-d "{\"msgtype\":\"markdown\",\"markdown\":{\"content\":\"## 🚨 WAF告警\n- **规则ID**: $RULE_ID\n- **来源IP**: $SRC_IP\n- **请求URI**: $URI\n- **时间**: $(date)\"}}"
fi
done
SCRIPT
chmod +x /opt/waf-alert.sh
ELK集成
# Filebeat配置
filebeat.inputs:
- type: log
paths:
- /var/log/modsecurity/modsec_audit.log
multiline.pattern: '^--'
multiline.negate: true
multiline.match: after
output.elasticsearch:
hosts: ["localhost:9200"]
index: "modsecurity-%{+yyyy.MM.dd}"
性能优化
# 1. 只对动态请求开启WAF
location ~* \.(php|asp|aspx|jsp|cgi)$ {
modsecurity on;
modsecurity_rules_file /etc/nginx/modsecurity/modsecurity.conf;
proxy_pass http://backend;
}
# 2. 关闭响应体检测(节省CPU)
# modsecurity.conf中设置
SecResponseBodyAccess Off
# 3. 减少审计日志记录
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
# 4. 使用内存文件系统存储临时数据
SecTmpDir /dev/shm/modsecurity/tmp
SecDataDir /dev/shm/modsecurity/data
对比表
| 功能 | Cloudflare | Imperva | ModSecurity+CRS |
|---|---|---|---|
| SQL注入防护 | 优秀 | 优秀 | 优秀 |
| XSS防护 | 优秀 | 优秀 | 优秀 |
| CSRF防护 | 基础 | 优秀 | 基础 |
| Bot防护 | 优秀 | 优秀 | 需自定义 |
| DDoS防护 | 优秀 | 优秀 | 需配合 |
| 自定义规则 | 有限 | 完整 | 完整 |
| 日志分析 | 仪表盘 | 仪表盘 | 自建 |
| 部署方式 | 云 | 云/本地 | 本地 |
| 价格 | $20-200/月 | $5K+/年 | 免费 |
ModSecurity + OWASP CRS 的组合是全球使用最广泛的开源WAF方案。规则库每周更新,覆盖OWASP Top 10所有攻击类型。配合自定义业务规则,防护效果不输任何商业WAF。
评论