4.7 KiB
4.7 KiB
waf — Web 应用防火墙网关
基于 Go + coraza 的 WAF 网关,部署在 gateway 之前,终止 TLS 并按 SecLang 规则库匹配请求,未命中则转发到 gateway。
客户端 ──HTTPS──▶ waf:443 (终止 TLS + coraza 规则匹配) ──明文 HTTP──▶ gateway:8443 (鉴权 + 反代)
为什么是 Go
coraza-waf/coraza是 ModSecurity SecLang 的 Go 实现,100% 兼容 OWASP CRS v4net/http/httputil.ReverseProxy标准库反向代理,零第三方依赖- goroutine + net/http 吞吐量比 Python 高一个数量级
go build出单二进制,core/init.txt直接拉起
极客友好的规则系统
| 操作 | 命令 |
|---|---|
| 编辑规则 | vim rules/local/custom.conf |
| 校验语法 | ./waf.bin -test rules/local/custom.conf |
| 列出所有规则 | ./waf.bin -list |
| 测试输入 | ./waf.bin -check "/?id=1' OR '1'='1" |
| 热加载(不重启) | kill -HUP $(pgrep waf) |
| 临时禁用某文件 | mv rules/local/x.conf x.conf.bak && kill -HUP $(pgrep waf) |
规则文件组织
rules/
├── waf.conf # 主入口,Include 各子文件
├── local/ # 本地自定义规则(ID 段 100000-199999)
│ ├── custom.conf # 示例:SQL注入/XSS/路径遍历/命令注入/扫描器UA
│ └── exceptions.conf # 误报白名单(SecRuleRemoveById / ctl:ruleRemoveById)
└── crs/ # OWASP CRS(git clone,不入库,ID 段 900000-999999)
规则 ID 分段
100000-199999本地自定义900000-999999OWASP CRS
规则语法(SecLang)
SecRule REQUEST_URI|ARGS "@rx (?i)union[\s/*]+select" \
"id:100001,phase:1,deny,status:403,log,msg:'SQL injection: UNION SELECT'"
字段说明:
REQUEST_URI|ARGS匹配目标(URI / 参数 / Header / Cookie 等)@rx ...正则匹配(也支持@pm、@contains、@beginsWith等)phase:1请求头阶段 /phase:2请求体阶段 /phase:3响应头 /phase:4响应体deny,status:403命中后动作msg命中日志描述
部署形态
WAF 必须终止 TLS 才能看到明文 body,因此证书需从 gateway 迁到 WAF:
- 把
gateway的full_chain.crt/server.key复制到waf/certs/ gateway改为监听127.0.0.1:8443,关闭 TLS(仅本机)waf监听:443,转发到http://127.0.0.1:8443
配置
config.yaml:
listen: ":443"
tls_cert: "./certs/full_chain.crt"
tls_key: "./certs/server.key"
upstream: "http://127.0.0.1:8443"
rules_dir: "./rules"
目录结构
waf/
├── main.go # 入口:服务模式 + CLI 子命令
├── config.yaml # 配置
├── go.mod
├── internal/
│ ├── engine/
│ │ └── engine.go # coraza 封装:加载/热加载/列举/单测
│ └── proxy/
│ └── proxy.go # ReverseProxy + WAF 事务接入
├── rules/
│ ├── waf.conf
│ └── local/
│ ├── custom.conf
│ └── exceptions.conf
├── _set.sh # 编译
├── _run.sh # 运行
├── .gitignore
└── README.md
安装
# 1. 安装 Go 1.21+
brew install go # macOS
# 或 sudo apt install golang-go # Debian/Ubuntu
# 2. 编译
bash _set.sh
# 3. 准备证书
mkdir certs && cp /path/to/full_chain.crt /path/to/server.key certs/
# 4. 运行
bash _run.sh
接入 core 自启动
在 core/init.txt 增加:
bash /opt/micro_servers/waf/_run.sh
并把 gateway 改为内部 HTTP 端口(不再监听 443)。
命中日志
命中规则时输出 JSON 一行,便于 jq 分析:
{"ts":"2026-07-25T10:00:00Z","action":"block","rule_id":100001,"ip":"1.2.3.4","method":"GET","path":"/","query":"id=1'+OR+'1'='1","ua":"curl/8.0","cost_ms":0}
聚合统计:
journalctl -u Nidus -o cat | grep '"action":"block"' | \
jq -r '.rule_id' | sort | uniq -c | sort -rn
启用 OWASP CRS(可选)
cd rules
git clone --depth 1 https://github.com/coreruleset/coreruleset.git crs
在 rules/waf.conf 取消注释:
Include crs/coraza.conf
Include crs/rules/*.conf
然后 kill -HUP $(pgrep waf)。
已知限制
- 请求体全量读入内存检测,10MB 上限(
SecRequestBodyLimit)。大文件上传场景需调大或加白名单。 - 响应体检测未启用(需缓冲整个响应,延迟成本高)。
- 限流/黑白名单未实现,可后续作为 coraza 规则或独立中间件加。
依赖
- Go 1.21+
- github.com/corazawaf/coraza/v3 v3.7.0
- gopkg.in/yaml.v3
许可证
MIT License