☰
开源网站防火墙SamWaf:独立引擎如何低成本实现SQL注入与CC攻击防护
2026/10/31 9:43:20 网站建设 项目流程

简介:SamWaf是一款开源轻量级网站防火墙,面向小公司、工作室和个人网站,支持完全私有化部署,数据加密仅存本地,一键启动即可运行于Linux、Windows 64位与Arm64环境。其核心防护引擎完全独立,不依赖IIS或Nginx,提供自定义规则、IP黑名单、URL白名单、CC访问限制、分站防护策略、SSL证书自动申请与续签、IPv6支持等功能,适合需要快速搭建Web安全防护的开发者与运维者。本次分享的源码包共701个文件、约20MB,以Go源码为主(493个go文件),辅以conf配置、png图标、md文档及yml文件等,结构清晰,并包含OWASP CRS规则集与自定义拦截界面,便于研究防护逻辑与进行二次开发。该资源已有99人学习下载,适合具备一定Go基础的读者,通过阅读源码可掌握报文解析、规则引擎、日志加密及隐私脱敏等关键实现思路。

1. 单机也能扛住扫描和 CC:SamWaf 开源网站防火墙源码到底解决什么问题

一个不争的事实是:小公司、工作室和个人网站的流量,从来就没少挨过打。服务器刚上线三天,日志里就开始出现SELECT、UNION、<script>的扫描痕迹;某个下午流量突然上涨,页面全部 502,一看是被人刷了 CC。买商业 WAF 吧,一年几千上万,按 QPS 计费的模式对小流量站点根本不划算;用云厂商的免费额度,又意味着把访问日志和拦截记录交到别人手里。我最早遇到这种情况时的第一反应是找一款能完全私有化部署的开源 Web 防火墙,而 SamWaf 开源源码就是在这个诉求下进入视野的。它定位非常明确:轻量、独立引擎、数据只留本地,自带 OWASP CRS 规则集,能防扫描、防注入、防 XSS、防 CC,还支持多网站单独配置防护策略。没有复杂的集群架构,一台普通云主机就能跑起来。适合两类人:一类是手里有真实站点、想低成本获得完整防护能力的小团队和个人站长;另一类是想研究 WAF 内部实现、愿意读 Go 代码并自己改规则引擎的开发者。下面从引擎设计开始,把这份源码里真正影响使用体验的部分拆开讲。

2. 独立引擎设计:为什么可以不依赖 Nginx/IIS,以及源码包里有哪些东西

2.1 轻量级 Web 防火墙的两种路线:插件集成与独立引擎

市面上常见的开源防护方案大多走“寄生”路线:要么做成 OpenResty 的 Lua 模块,挂在 Nginx 里;要么以 IIS 筛选器或 Apache 模块的形式嵌入现有 Web 服务。这类方案的优点是请求处理路径短、性能开销小,但缺点同样明显——一旦你的 Web 服务不是 Nginx/IIS,或者你想频繁切换后端,整套防护逻辑就要跟着重写。而且模块型 WAF 的规则升级往往和主服务版本绑定,一个规则写崩了,可能连正常业务一起拖垮。

SamWaf 走的是另一条路:独立引擎。它自己监听一个端口,流量先进到 SamWaf,做完全部检查后再转发给后端的真实 Web 服务。这样做带来的直接好处有三个:第一,后端换成 Tomcat、Apache、IIS 或者随便什么静态文件服务都不影响防护逻辑,因为防护层和后端解耦了;第二,独立进程的内存隔离和崩溃恢复比模块内嵌更可控,规则引擎出问题顶多拦截页面报错,不会让后端进程直接挂掉;第三,部署形态灵活,既能本机监听,也能作为前置网关部署在独立的小机器上。代价是需要调整站点的端口关系,这是用独立引擎必须接受的成本。

2.2 源码目录与构建脚本:UPX、Docker、Win7 各管什么

源码包里没有花哨的目录结构,一眼就能看出这是一个以工程落地为导向的项目。release_pub.bat和release_pub_test.bat是发布脚本,前者用于正式发布流程,后者用于测试环境发布;build_docker_release_linux.bat是 Linux 下的 Docker 镜像构建脚本;build-releases-win-upx.bat和build-releases-win7-upx.bat分别对应 Windows 常规版和 Windows 7 兼容版的构建,两者都调用了 UPX 做可执行文件压缩。

# 以 Windows 发布版构建为例,常见的构建流程可以拆成三步: # 1. 先编译出原始的可执行文件 CGO_ENABLED=0 go build -ldflags="-s -w" -o samwaf.exe ./cmd/samwaf # 2. 用 UPX 压缩,减少发布包体积 upx --best --lzma samwaf.exe -o samwaf_upx.exe # 3. 把压缩后的文件配合 conf 和规则目录一起打进发布包

这里几个参数值得说明:CGO_ENABLED=0是强制纯静态编译,保证生成的 exe 不需要额外运行时 DLL,这也是它能在 Windows 7 上直接跑的前提;-ldflags="-s -w"去掉符号表和调试信息,既减体积也减少被逆向分析的面;UPX 的--best --lzma是最高压缩比模式,代价是启动时多一次内存解压,对 WAF 这种常驻进程影响很小。如果你自己打包时发现杀毒软件报毒,把第二步的 UPX 去掉重编就能定位问题来源,这事后面避坑章节还会展开。

注意到源码包里还有 4 个 OWASP CRS 的 conf 规则文件,分别是REQUEST-920-PROTOCOL-ENFORCEMENT.conf、REQUEST-932-APPLICATION-ATTACK-RCE.conf、REQUEST-941-APPLICATION-ATTACK-XSS.conf、REQUEST-942-APPLICATION-ATTACK-SQLI.conf。也就是说,SamWaf 并不是把全部 CRS 规则硬塞进来,而是按攻击类型摘选了协议校验、远程命令执行、XSS、SQL 注入这四类最常用的规则集,这符合它“轻量级”的定位——规则太多必然带来误报和维护成本,对小型站点来说这四类覆盖面已经足够。

2.3 请求过滤链路:黑名单、CC 和规则集的执行顺序

独立引擎的过滤链路决定了规则之间的协作方式。在 SamWaf 的实际处理流程中,一个请求进入后会依次经过几个检查点,顺序大致是:先做全局和分站的黑名单检查,判断来源 IP 是否被封禁;接着走白名单逻辑,命中白名单的 IP 或 URL 直接放行,不再做后续深度检查;然后是 URL 访问限制和 CC 频率检测,这两个维度一个看路径、一个看时间窗口内的请求次数;最后才进入 CRS 规则集和自定义规则的匹配,也就是对请求体、头部、参数的深层内容检测。全部通过后,请求才会被转发到真实后端。

这个顺序的合理性在于,成本和收益是递增的:IP 黑名单是 O(1) 级别的匹配,成本最低所以放最前面;白名单放第二可以避免对信任来源做无意义的正则运算;CC 检测基于计数器,只消耗少量内存;而 CRS 规则的正则匹配最重,放在最后能让大部分恶意请求在前面几层就被拦截掉,减轻规则引擎的负载。理解这个链路,后面配置自定义规则和排查拦截不生效时思路会清晰很多。

3. 把 SamWaf 跑起来:构建、一键启动与全局防护配置

3.1 Linux Docker 构建与 Windows 发布版启动

SamWaf 在 Linux 下最常见的部署方式是用 Docker,源码里已经提供了build_docker_release_linux.bat,它本质上是在帮你自动化完成镜像构建。如果没有现成镜像,手动构建和启动的流程也就两条命令的事。

# 在源码根目录执行,构建本地镜像 docker build -t samwaf:latest . # 启动容器,宿主机 80 端口映射到容器 8080 端口 docker run -d --name samwaf-server \ -p 80:8080 \ -v /opt/samwaf/data:/app/data \ -v /opt/samwaf/logs:/app/logs \ -v /opt/samwaf/certs:/app/certs \ samwaf:latest

这里把数据、日志和证书目录全部挂载出来是必须养成的习惯。/app/data存数据库和配置,/app/logs存加密日志,/app/certs存放自动申请的 SSL 证书。如果不挂载这三个目录,容器销毁后防火墙配置、拦截日志和证书全部丢失,续签周期也会被打断。端口映射方面,宿主机 80 端口对外提供服务,容器内 8080 是 SamWaf 自己的监听端口,实际使用中你需要把原网站的监听地址改成127.0.0.1:8080之外的内部端口,让流量先走 SamWaf 再回源。

Windows 部署则更简单。用build-releases-win-upx.bat构建出 win 发布包后,解压直接运行主程序即可。它自带 GUI 配置界面,不需要安装任何运行时环境。首次启动会默认监听一个本地管理端口,浏览器访问后进入初始化流程。Windows 版的注意点是防火墙入站规则要允许程序监听,否则外网访问不到管理界面,这个容易被系统自带防火墙挡住。

3.2 首次登录:添加网站、指向源站、开启防护

启动完成后,第一件事是把真实站点添加进 SamWaf。登录管理界面后找到网站管理入口,添加网站时需要填写三个关键信息:站点域名、后端源站地址、监听端口。这里的源站地址是 SamWaf 转发流量的目的地,它可以是本机的另一个端口,也可以是内网另一台 Web 服务器。比如你原来的 Nginx 监听 80 端口,那可以把 Nginx 改成监听 8081,然后让 SamWaf 监听 80 并把流量转发到 127.0.0.1:8081。

# 验证转发配置是否生效,用 curl 直接请求 WAF 入口 curl -I http://your-domain.com/ # 正常响应会返回 200 和源站的实际 Server 头 # 如果返回 502,说明 SamWaf 到源站的连接失败,检查源站端口

这一步最容易踩的坑是“转发环路”:如果 SamWaf 的源站地址填了自己的监听端口,流量就会在防火墙和后端之间死循环,直接造成 502 或者连接超时。添加完网站且验证 200 响应后,再进入全局防护策略页面,把 CC 频率限制、IP 黑名单、CRS 规则集这几个开关一次性打开。全局配置的好处是默认覆盖所有网站,后面再按站点单独微调,这也是摘要里说的“支持全局一键配置”。

3.3 日志加密与数据落盘:隐私是怎么保住的

很多小站点不引入 WAF 的顾虑不是性能,而是数据隐私:防火墙会记录所有请求日志,这些日志如果明文存放在第三方平台,等于把访问记录、POST 参数、用户 IP 全部交出去。SamWaf 的处理方式是日志加密保存和通讯日志加密。本地日志以加密形式写盘,管理界面上看到的是解密后的内容,但磁盘文件直接拷走是没有可读性的;通讯日志则对传输过程加密,避免管理端和引擎之间的数据流被截获。

# 日志目录结构参考,加密文件与配置文件分离 /opt/samwaf/logs/ access.log.enc # 加密的访问日志 attack.log.enc # 加密的攻击拦截日志 keys/ # 日志加密密钥目录,务必保留

这里要特别提醒:keys目录是日志加密的密钥所在,备份日志前先备份这个目录。有人做过血的教训,迁移服务器时只拷贝了.enc日志文件没拷贝密钥,结果历史日志全部无法解密,等于失去了一整年的攻击溯源数据。另外管理界面通常提供“信息脱敏”选项,开启后日志和拦截记录里的手机号、邮箱、身份证号等敏感字段会被替换成掩码,这个开关建议默认打开。信息脱敏造成的另一个影响是,脱敏后的日志无法还原原始参数,做安全分析时只能看攻击特征,这一点要提前知道。

4. 防护规则实战:OWASP CRS 规则集与自定义规则的协同

4.1 内置四个 CRS 规则:SQL、XSS、RCE、协议校验

前面提到源码包里带了 4 个 OWASP CRS 规则文件,这里展开说明各自的职责范围,方便你在调规则时有据可依。这四个文件不是完整 CRS 的全量导入,而是摘选出的四个攻击面,正好覆盖了公网 Web 最常见的四类恶意请求。

规则文件检测目标典型攻击样例
REQUEST-920-PROTOCOL-ENFORCEMENT.conf协议异常、畸形请求、编码绕过非标准 HTTP 方法、畸形的 Content-Length
REQUEST-932-APPLICATION-ATTACK-RCE.conf远程命令执行、代码执行system(id)、${IFS}whoami、Runtime.exec
REQUEST-941-APPLICATION-ATTACK-XSS.confXSS 跨站脚本、HTML 注入<script>alert(1)</script>、javascript:伪协议
REQUEST-942-APPLICATION-ATTACK-SQLI.confSQL 注入、数据库攻击' OR '1'='1、UNION SELECT、sleep(3)

实际使用中,920 协议校验规则的误报率通常最高,它会对不符合 RFC 规范的请求直接拦截,而一些老业务系统的客户端会发出带非法字符的请求。常见做法是先单独开启 920 观察一段时间,把误报较多的站点加进 URL 白名单,再逐步放开。932 的 RCE 规则对国内站点尤其重要,因为很多历史遗留系统都存在命令拼接漏洞,被扫描器打穿的概率不小。

4.2 自定义防护规则的写法与生效范围

CRS 规则是通用防线,但真实业务里总有一些专属攻击特征需要单独匹配,比如你的登录接口被定向爆破、某个参数总被尝试注入特殊的业务关键字。SamWaf 的自定义规则支持两种编辑方式:脚本编辑和界面编辑。界面编辑适合非开发人员,通过下拉选择匹配字段和动作;脚本编辑则适合批量维护规则,直接写成配置文件再加载。

# 自定义规则示例:拦截带敏感文件路径的请求 rule: name: "block-sensitive-path" enabled: true scope: "global" # global 全局生效,site 指定站点生效 condition: - field: "uri" operator: "contains" value: ["/etc/passwd", "/.git/", "/WEB-INF/"] action: "block" # block 拦截,log 仅记录 message: "sensitive path access blocked"

这段配置做了三件事:scope: "global"让规则全局生效,所有站点都受保护;condition里检查 URI 是否包含常见的敏感路径,命中任意一个即触发;action: "block"是直接拦截并返回自定义拦截页面。如果你不确定规则会不会误伤,先把action改成log,跑一周看命中记录,确认没有正常请求命中后再切到block,这是上线新规则最稳妥的顺序。operator参数除了contains,通常还支持regex和equals,正则匹配能力更强但性能开销更大,优先用contains,搞不定再上正则。

4.3 白名单、黑名单、URL 限制的优先级参考

多套规则同时开启时,最怕的是规则之间互相打架。我一般会按这个优先级顺序约定:IP 白名单最高,命中直接放行;IP 黑名单次之,命中直接拦截;URL 白名单优先于 URL 访问限制;自定义规则优先于 CRS 规则;最后才是 CC 频率限制。也就是说,一个来自白名单 IP 的请求即使 URL 命中限制规则,也会被放行,因为白名单在前置链路已经短路返回。

# 常用白名单配置场景:把健康检查请求放行 # 界面路径:白名单访问 -> 添加 URL 白名单 # 示例值: # 类型:URL 前缀 # 值:/healthz /ping # 备注:避免监控告警误触发 CC 拦截

这里的 IP 白名单和 URL 白名单是两套独立配置,前者针对来源地址,后者针对请求路径。健康检查类的请求经常会被 CC 频率限制误伤,因为监控系统每分钟请求一次,频率叠加后可能超过阈值。把/healthz、/ping加入 URL 白名单是成本最低的解决方案,不需要调高全局频率阈值,也不会削弱其他路径的防护强度。同理,你自己的办公网出口 IP 应该加入 IP 白名单,避免调试接口时被频繁拦截。

5. 避坑指南:SamWaf 排查最常见的五个问题

5.1 黑名单没生效

现象:把攻击来源 IP 加进了 IP 黑名单,界面显示已封禁,但该 IP 的请求依然能打到后端正常返回。原因:黑名单只在“全局防护策略”的相应站点开启了才生效。我见过好几个案例是把 IP 加进黑名单了,但对应网站的防护策略里没有勾选“启用 IP 黑名单”这个开关,或者黑名单级别只设成了“记录”而不是“拦截”。解决:检查全局策略和分站策略里的黑名单开关,把动作从“仅记录”改为“拦截”,保存后再次用该 IP 发起请求,确认返回的是拦截页面而不是业务页面。

5.2 CC 频率限制误伤正常用户

现象:业务高峰期,大量正常用户访问页面时被拦截,提示访问频繁。原因:CC 频率阈值设置过低,导致多人共用出口 IP(比如公司 NAT、学校网络)时整体频率被误判为攻击。解决:在 CC 频率设置里调高时间窗口或调低允许次数;把已知的公共出口 IP 加入 IP 白名单;更精细的做法是把静态资源路径(.js、.css、.png)加入 URL 白名单,因为这些资源请求量大但不存在业务危险,真正需要频率限制的是动态接口路径。

5.3 UPX 压缩导致杀毒软件误报

现象:Windows 发布版解压后,杀毒软件直接提示木马并隔离主程序。原因:UPX 加壳后可执行文件的特征码容易触发启发式查杀,这是 UPX 压缩工具的已知问题,不是程序本身有问题。解决:如果你确认源码是从官方渠道获取的,对杀毒软件添加目录信任;更稳妥的方案是重新编译,去掉 UPX 压缩步骤,直接发布未压缩版本。我自己平时构建 Windows 版时会出两个包,压缩版用于分发,未压缩版备用。

5.4 SSL 证书自动续签失败

现象:证书到期前自动续签没有成功,浏览器提示证书过期。原因:续签验证方式不同导致的,常见有两种——DNS 验证失败是因为域名的 DNS 托管在第三方平台而没有配置 API 授权;HTTP 验证失败则是因为 80 端口的验证请求被自己的防护规则拦截了,典型的是 920 协议校验对 ACME 验证请求的 UA 不友好。解决:先看证书验证日志确认失败阶段,如果是 HTTP 验证被拦,把 Let's Encrypt 的验证路径加入 URL 白名单;如果是 DNS 验证,到域名商控制台补上自动续签所需的 API 凭证。

5.5 日志加密后无法导出排查

现象:想导出历史攻击记录做分析,发现导出文件打不开,或者迁移服务器后旧日志全部不可读。原因:日志采用加密保存,导出/解密依赖本地密钥文件,密钥缺失或迁移时漏拷就无能为力了。解决:迁移时把整个日志目录连同keys子目录一起拷贝,不要只复制.enc文件。日常备份也遵循同样的原则,密钥和数据必须同时备份。这个问题的解决成本完全前置,等需要的时候才想起来就已经晚了。

6. 进阶技巧:把拦截页面和证书检查变成日常巡检习惯

6.1 自定义拦截页面与隐私脱敏

默认拦截页面样式简陋,用户访问被拦截的路径时容易误以为站点挂了。SamWaf 支持自定义拦截界面,动手改一下很有必要。我会把拦截页改造成带站点 Logo、错误码和简短说明的样式,并在页面里隐藏真实 IP 和请求详情,只显示一个“访问被安全策略拦截”的通用提示。自定义页面配置里通常可以引用变量,比如规则名称和拦截类型,但注意这些变量可能包含原始请求参数,发布前要确认站点开启了信息脱敏,否则拦截页会反向泄露攻击载荷里的敏感信息。

6.2 IPv6 场景的访问控制

现在不少小站已经上了 IPv6,SamWaf 对 IPv6 的支持意味着黑名单和白名单也支持 IPv6 地址段。这里有一个容易被忽略的细节:同一台机器的 IPv4 和 IPv6 出口地址是不同的,攻击者完全可能用 IPv6 地址绕过只配了 IPv4 的黑名单。配置黑名单时,把已知攻击源的 IPv4 和 IPv6 地址都拉黑才完整。同时注意日志记录里 IPv6 地址的格式,压缩格式和完整格式在规则匹配时语义相同,但字符串匹配却可能失配,所以对 IPv6 地址的规则建议用 CIDR 匹配而不是精确字符串匹配。

6.3 一次标准验证的 curl 流程

部署任何防火墙后,我习惯做一组标准验证,确认防护动作真实生效而不是纸上谈兵。这套流程在 SamWaf 上同样适用,全部用 curl 完成,不带任何窗口界面依赖。

# 1. 验证 SQL 注入拦截,预期返回拦截页(通常 403 或自定义页面) curl -i "http://your-domain.com/news?id=1' AND '1'='1" # 2. 验证 XSS 拦截 curl -i "http://your-domain.com/search?q=<script>alert(1)</script>" # 3. 验证正常请求放行,预期返回 200 curl -i "http://your-domain.com/" # 4. 验证 CC 拦截:短时间内连续请求 100 次,观察是否触发频率限制 for i in $(seq 1 100); do curl -s -o /dev/null -w "%{http_code}\n" "http://your-domain.com/" ; done

这个流程跑完之后,看一眼攻击日志里的拦截记录是否同步生成,如果 curl 返回了拦截页但日志里没有记录,说明日志落盘有问题,需要尽快排查;反过来,如果日志有记录但页面返回了业务内容,说明动作没有正确执行。从那以后我每次部署完 SamWaf 都会强制走一遍这套验证流程,确认拦截与放行行为符合预期,同时把证书检查和日志备份也放进每周的例行巡检清单里,希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询