fabriziosalmi/caddy-waf

GitHub: fabriziosalmi/caddy-waf

面向 Caddy Web 服务器的 Web 应用防火墙中间件,提供正则规则检测、IP/DNS/GeoIP 过滤、Tor 阻断和速率限制等防护能力。

Stars: 791 | Forks: 30

# Caddy WAF 一个用 Go 编写的、面向 [Caddy](https://caddyserver.com/) Web 服务器的 Web Application Firewall 中间件。 [![测试](https://static.pigsec.cn/wp-content/uploads/repos/cas/ce/ce733292a922c08274cf5a2096f8fa4cf01023bfa51a36ef6beecaaef371a9d9.svg)](https://github.com/fabriziosalmi/caddy-waf/actions/workflows/test.yml) [![CodeQL](https://static.pigsec.cn/wp-content/uploads/repos/cas/53/539e9a6bf48ad24469a4363bff3aa68124154549e26592783d3d8577f2acbbfc.svg)](https://github.com/fabriziosalmi/caddy-waf/actions/workflows/github-code-scanning/codeql) [![构建、运行和验证](https://github.com/fabriziosalmi/caddy-waf/actions/workflows/build-run-validate.yml/badge.svg)](https://github.com/fabriziosalmi/caddy-waf/actions/workflows/build-run-validate.yml) - **模块 ID**:`http.handlers.waf` - **Go module 路径**:`github.com/fabriziosalmi/caddy-waf` - **当前版本**:`v0.3.4`(见 [`caddywaf.go`](caddywaf.go) — `const wafVersion`) - **许可证**:AGPL-3.0 ## 概述 `caddy-waf` 是一个 HTTP handler 中间件,它通过四个定义明确的阶段检查请求和响应,应用带有异常评分的正则表达式规则集,执行 IP/DNS/ASN/国家黑名单和白名单,执行 token-bucket 风格的速率限制,并暴露一个 JSON 指标 endpoint。 该中间件作为单个 Caddy 模块实现,注册 ID 为 `http.handlers.waf`。它可以通过 Caddyfile 或直接通过 JSON 进行配置。 ## 功能特性 | 功能特性 | 实现方式 | |---|---| | 正则规则引擎 | Go [`regexp`](https://pkg.go.dev/regexp) 包(RE2,线性时间保证)。编译后的模式按规则 ID 进行缓存。 | | 多阶段检查 | 阶段 1(请求标头和请求前检查),阶段 2(请求体),阶段 3(响应标头),阶段 4(响应体)。 | | 异常评分 | 每条规则将其 `score` 贡献到单次请求的总分中;当总分达到 `anomaly_threshold` 时,请求将被阻止。 | | 显式动作 | 规则 `mode` 为 `block` 或 `log`。`block` 短路请求;`log` 记录匹配并继续。 | | IP 黑名单 | 存储 prefix trie([`go-iptrie`](https://github.com/phemmer/go-iptrie))中的纯 IP 和 CIDR 范围(IPv4 和 IPv6)。 | | DNS 黑名单 | 精确匹配(不区分大小写)的主机查找。 | | GeoIP 国家阻止 / 白名单 | MaxMind GeoLite2 Country MMDB。 | | ASN 阻止 | MaxMind GeoLite2 ASN MMDB。 | | Tor 出口节点阻止 | 定期从 `https://check.torproject.org/torbulkexitlist` 获取。 | | 速率限制 | 基于单 IP 的滑动窗口,可选的正则表达式 path 匹配。 | | 自定义阻止响应 | 针对每个状态码响应自定义 Content-Type、标头和主体(内联或来自文件)。 | | 敏感数据脱敏 | 可选地对敏感查询参数和日志字段进行脱敏。 | | 热重载 | 对规则文件、IP 黑名单和 DNS 黑名单使用 `fsnotify` 监视器。 | | 指标 endpoint | 在配置的 `metrics_endpoint` 路径暴露的 JSON 文档。 | | 异步日志记录 | 带有同步回退机制的缓冲日志通道(当缓冲区满时)。 | ## 工程说明 - **线性时间正则表达式**:规则由 Go 的 `regexp` (RE2) 编译。不会发生灾难性回溯。 - **无等待计数器**:每条规则的命中计数使用存储在 `sync.Map` 中的 `atomic.Int64`。 - **有界主体读取**:请求体通过 `io.LimitReader`(`max_request_body_size`,默认 10 MiB)读取,并通过 `io.MultiReader` 恢复,因此下游 handler 仍能看到完整的主体。 - **有界响应缓冲**:仅当存在阶段 4 规则对其进行检查时,响应体才会被保存在内存中,并且绝不会超过 `max_response_body_size`(默认 10 MiB)。超过此限制——或在上游刷新时——WAF 会释放其持有的内容并 stream 剩余部分,因此内存绝不会随着响应大小而增加。 - **零拷贝主体字符串**:主体通过 `unsafe.String` 暴露给规则匹配,以避免每次请求产生内存分配。 - **GeoIP 的熔断器**:`geoip_fail_open` 控制 GeoIP 查找失败是阻止请求还是允许其通过。 - **Panic 恢复**:`ServeHTTP` 安装了一个延迟恢复机制,在发生 panic 时返回 `500 Internal Server Error`。 ## 快速开始 实现可运行构建的最快途径: ``` curl -fsSL -H "Pragma: no-cache" \ https://raw.githubusercontent.com/fabriziosalmi/caddy-waf/refs/heads/main/install.sh | bash ``` 该脚本确保安装了 Go 和 `xcaddy`,克隆仓库,下载 GeoLite2 数据库,使用 `caddy-waf` 模块构建 Caddy,并启动服务器。 一份典型的配置日志: ``` INFO Provisioning WAF middleware {"log_level":"info","log_path":"debug.json","log_json":true,"anomaly_threshold":20} INFO http.handlers.waf Tor exit nodes updated {"count":1093} INFO WAF middleware version {"version":"v0.3.4"} INFO Rate limit configuration {"requests":100,"window":10,"cleanup_interval":300,"paths":["/api/v1/.*"],"match_all_paths":false} WARN GeoIP database not found. Country blacklisting/whitelisting will be disabled {"path":"GeoLite2-Country.mmdb"} INFO IP blacklist loaded {"path":"ip_blacklist.txt","valid_entries":223770,"invalid_entries":0,"total_lines":223770} INFO DNS blacklist loaded {"path":"dns_blacklist.txt","valid_entries":854479,"total_lines":854479} INFO WAF rules loaded successfully {"total_rules":33,"rule_counts":"Phase 1: 17 rules, Phase 2: 16 rules, Phase 3: 0 rules, Phase 4: 0 rules, "} INFO WAF middleware provisioned successfully ``` ## 安装说明 ### 要求 - Go **1.25** 或更高版本([`go.mod`](go.mod) 声明了 `go 1.25`) - Caddy **v2.11.x** 或更高版本(当前构建使用 `github.com/caddyserver/caddy/v2 v2.11.2`) - [`xcaddy`](https://github.com/caddyserver/xcaddy) 用于构建带有插件的 Caddy ### 选项 1 — 使用 xcaddy 构建(推荐) ``` go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest xcaddy build --with github.com/fabriziosalmi/caddy-waf ./caddy list-modules | grep waf # expect: http.handlers.waf ``` ### 选项 2 — 快速脚本 ``` curl -fsSL -H "Pragma: no-cache" \ https://raw.githubusercontent.com/fabriziosalmi/caddy-waf/refs/heads/main/install.sh | bash ``` ### 选项 3 — 从源码构建 ``` git clone https://github.com/fabriziosalmi/caddy-waf.git cd caddy-waf go mod tidy wget https://git.io/GeoLite2-Country.mmdb # optional, only for GeoIP xcaddy build --with github.com/fabriziosalmi/caddy-waf=./ ./caddy fmt --overwrite ./caddy run ``` ### `caddy add-package` 此模块在 Caddy 的官方包注册表中**未注册**;`caddy add-package github.com/fabriziosalmi/caddy-waf` 将失败并返回 `HTTP 400: ... is not a registered Caddy module package path`。请使用上述构建选项之一。详情请见 [`docs/add-package-guide.md`](docs/add-package-guide.md)。 ## 最小化 Caddyfile ``` { auto_https off admin localhost:2019 } :8080 { log { output stdout format console level INFO } route { waf { metrics_endpoint /waf_metrics rule_file rules.json ip_blacklist_file ip_blacklist.txt dns_blacklist_file dns_blacklist.txt } @wafmetrics path /waf_metrics handle @wafmetrics { # Falls through to the WAF handler, which serves metrics as JSON. } handle { respond "Hello world!" 200 } } } ``` [`Caddyfile`](Caddyfile) 和 [`caddyfile.example`](caddyfile.example) 中提供了带有完整注释的示例。 ## 文档 | 文档 | 主题 | |---|---| | [`docs/installation.md`](docs/installation.md) | 所有安装方法。 | | [`docs/configuration.md`](docs/configuration.md) | Caddyfile 和 JSON 指令、请求生命周期、阻止优先级。 | | [`docs/rules.md`](docs/rules.md) | `rules.json` schema、目标标识符、正则表达式语义。 | | [`docs/blacklists.md`](docs/blacklists.md) | IP 和 DNS 黑名单文件格式。 | | [`docs/ratelimit.md`](docs/ratelimit.md) | 速率限制块、路径匹配、行为。 | | [`docs/geoblocking.md`](docs/geoblocking.md) | 国家阻止 / 白名单、ASN 阻止、回退行为。 | | [`docs/attacks.md`](docs/attacks.md) | 内置规则集解决的攻击类别。 | | [`docs/dynamicupdates.md`](docs/dynamicupdates.md) | 文件监视器、重载语义、每次重载的范围。 | | [`docs/metrics.md`](docs/metrics.md) | `/waf_metrics` JSON schema。 | | [`docs/prometheus.md`](docs/prometheus.md) | 将 JSON 指标桥接到 Prometheus 和 Grafana。 | | [`docs/caddy-waf-elk.md`](docs/caddy-waf-elk.md) | 使用 Filebeat 将日志发送到 ELK stack。 | | [`docs/scripts.md`](docs/scripts.md) | 用于生成规则和黑名单的辅助 Python 脚本。 | | [`docs/testing.md`](docs/testing.md) | 运行内置的 `test.py` 测试套件。 | | [`docs/docker.md`](docs/docker.md) | 使用 Docker / Docker Compose 构建和运行。 | | [`docs/add-package-guide.md`](docs/add-package-guide.md) | `caddy add-package` 注册状态。 | | [`docs/caddytest.md`](docs/caddytest.md) | `caddytest.py` 流量生成工具。 | ## 项目结构 ``` . ├── caddywaf.go Module registration, lifecycle, file watchers, metrics endpoint ├── handler.go ServeHTTP, phase dispatch, blocking decisions ├── config.go Caddyfile directive parsing ├── rules.go Rule loading, validation, regex caching, hit accounting ├── request.go Target extraction (URI, headers, body, JSON paths, ...) ├── response.go Response recorder, block writer ├── blacklist.go IP and DNS blacklist loaders and lookups ├── ratelimiter.go Per-IP / per-path sliding-window rate limiter ├── geoip.go MaxMind country and ASN lookups, with optional cache ├── tor.go Periodic Tor exit-node list fetcher ├── logging.go Async log worker, sensitive-data redaction ├── helpers.go IP parsing helpers ├── types.go Public types (Middleware, Rule, RateLimit, ...) ├── doc.go Package documentation ├── rules.json Default rule set (used by Caddyfile) ├── rules/ Modular rule files by category ├── ip_blacklist.txt Default IP blacklist ├── dns_blacklist.txt Default DNS blacklist ├── tor_blacklist.txt Tor exit-node cache (auto-managed) ├── docs/ Documentation └── *_test.go Unit and integration tests ``` ## 测试 ``` make test # go test -v ./... make it # go test -v ./... -tags=it (integration) make lint # golangci-lint run make test-integration # runs test.py inside a python:3.9-slim container ``` 该仓库还附带了 Python 套件,涵盖恶意 payload(`test.py`)、流量生成(`caddytest.py`)和基准测试(`benchmark.py`)。请参见 [`docs/testing.md`](docs/testing.md) 和 [`docs/caddytest.md`](docs/caddytest.md)。 ## 安全 漏洞披露请参见 [`SECURITY.md`](SECURITY.md)。报告可以发送至 `fabrizio.salmi@gmail.com` 或作为私密的 GitHub Security Advisory 提交;请不要公开提 issue。 ## 许可证 AGPL-3.0。见 [`LICENSE`](LICENSE)。
标签:AppImage, Caddy, CISA项目, EVTX分析, Go, Ruby工具, WAF, Web应用防火墙, 中间件, 密码管理, 日志审计, 流量过滤, 网络安全, 配置错误, 隐私保护