ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

WAF落地不止反向代理:流量接入、代理选型与规则引擎实战

WAF落地不止反向代理:流量接入、代理选型与规则引擎实战

简介:《WAF的实现与架构演进》是一份面向安全工程师、运维人员与后端架构人员的技术演示文稿,围绕 Web 应用防火墙的能力边界、产品形态与架构演进展开,帮助读者厘清硬件盒子、软件 WAF 到云 WAF 的选型逻辑与落地路径。全包仅含 1 个 pptx 文件,约 3.93MB,以要点与图示组织内容。正文覆盖七层 HTTP(S) 流量检测,以及 SQL 注入、XSS、CSRF、恶意爬虫与 CC 攻击的识别阻断;横向对比绿盟、启明星辰、华为等硬件方案与安全狗、安恒明御等软件方案;拆解云 WAF 的流量接入(DNS 调度、CNAME、Anycast)、HTTP(S) 反向代理与安全规则引擎三大基础要点,并延伸至 Nginx/OpenResty 的 Lua 阶段扩展、ModSecurity CRS 与 Naxsi 的规则机制差异,以及 PASS、DENY、ALLOW、REDIRECT 等动作与匹配条件的配置写法。已有 315 人学习,适合需要搭建开源 WAF 或评估商用产品的中高级读者参考。

1. WAF 的真正边界:为什么“加一层反向代理”不等于安全

很多团队把 waf 当成在 Web 前面加一道墙,真正上线后才发现,墙的位置、砖缝和验收标准才决定成败。它做的不是“封 IP”这种粗活,而是对七层 HTTP(S) 流量做解析,在 URI、参数、请求头、响应体里识别 SQL 注入、XSS、命令注入、文件包含、敏感文件访问、CSRF、恶意爬虫和 CC 等行为,再按规则动作阻断或放行。反直觉的地方在于:同一套规则,放在主机插件、本地串行盒子或云反向代理里,命中率和延迟可能完全不同;WAF 的功底一半在规则,一半在流量接入和代理层。搞懂这条链路,才能判断误报是规则问题、解析问题,还是接入层根本没把真实客户端信息带进来。对做架构评审的人来说,这份资料真正值得先看的是三层之间的关系,而不是某一条规则写得多漂亮。

2. 流量接入:DNS 调度与 Anycast 如何决定第一跳

WAF 的形态大致分三类:本地硬件盒子串行或旁路部署、以模块或插件形式嵌在已有 Web 服务器里、以及以反向代理形态出现的云 WAF。前两类更像“把检测塞进现有路径”,第三类则要求用户流量先到 WAF 边缘节点,再由边缘节点回源。云 WAF 的实施要点通常被拆成三件事:流量接入、HTTP(S) 反向代理、安全规则引擎。顺序不能反,因为流量接不进来,代理层拿不到完整请求,规则引擎再强也只是离线正则库。

流量接入解决的是“第一跳去哪里”。正常访问流程里,浏览器先做 DNS 解析,拿到源站 IP 后直接建立连接;接入 WAF 后,DNS 解析结果要指向 WAF 的调度入口,再由调度系统决定落到哪个边缘节点。常见做法有 CNAME 接入和 NS 接入:CNAME 把业务域名指向 WAF 提供的调度域名,NS 则把整个域的权威解析交给 WAF 侧。前者迁移成本低,适合快速接入;后者控制力更强,但涉及权威 DNS 迁移,灰度周期更长。

2.1 CNAME 接入与 DNS 调度的生效边界

CNAME 接入的本质是把“业务域名解析”变成“调度域名解析”。用户访问shop.example.com,递归解析器发现它是waf.example.net的别名,继续解析调度域名,最终拿到某个边缘节点 IP。调度系统可以根据地域、运营商线路、机房负载、健康状态返回不同 IP。这样做的价值不只是隐藏源站,还能把攻击流量分散到多个清洗节点,或者在某个机房压力过大时把新解析请求分走。

下面是一个最小化的记录示意,只表达关系,不涉及真实域名:

# 业务域名通过 CNAME 指向 WAF 调度域名 shop.example.com. 300 IN CNAME waf.example.net. # 调度域名由 WAF 侧解析,按策略返回边缘节点 waf.example.net. 60 IN A 192.0.2.10

300是业务侧 CNAME 的 TTL,60是调度侧 A 记录的 TTL。TTL 越长,解析缓存越久,调度策略变更生效越慢;TTL 越短,解析请求越频繁,权威 DNS 压力越大。很多接入事故不是规则写错,而是 TTL 规划没做:攻击流量已经切走,旧缓存还把用户往原节点带;或者源站刚切到 WAF,部分递归解析器仍返回旧 IP,用户直连源站,WAF 日志里自然一条都看不到。

DNS 调度的优点是实现简单、对现有网络改动小,缺点也明显:它依赖递归解析器的缓存行为,调度粒度受 TTL 限制;解析链路变长后,首包延迟可能增加;遇到局部解析异常时,排障要同时看权威 DNS、递归 DNS 和本地缓存。更隐蔽的问题是,DNS 调度只能决定“新连接去哪里”,已经建立的长连接不会因为解析结果变化而迁移。对短连接 API 影响不大,对长轮询、WebSocket 这类业务,调度切换要考虑连接重建和客户端重试。

提示:接入前先确认业务里有没有长连接、强依赖源站 IP 的白名单、以及客户端侧固定 DNS 的情况,这三类最容易让 WAF 接入看起来成功、实际仍有流量绕过。

2.2 Anycast 的收益与 BGP 代价

Anycast 是另一种第一跳控制方式:同一个 IP 地址在多个边缘节点上同时宣告,网络路由协议会把用户流量带到“路由意义上最近”的节点。表现形式上和 DNS 调度有相似之处,都是让不同用户落到不同节点,但机制不同:DNS 调度返回的是不同 IP,Anycast 返回的是同一个 IP,靠路由层面选路。它的优点很直接:路由策略变动生效快,不必等 DNS 缓存过期;调度在路由层完成,对 DNS 解析性能要求低;单点故障后,路由撤销能让新流量自动切到其他节点。

代价同样明显。全球网络路由错综复杂,BGP 选路优化不是改一条规则就完事,节点之间的宣告范围、回源路径、故障收敛都要长期调;Anycast 需要持有可宣告的地址段,成本高,单节点也要占用同一段地址,存在地址浪费;同一个 IP 下,已有 TCP 连接不会因为路由切换而迁移,节点故障时长连接会断,应用层要有重试和幂等设计。更现实的问题是,Anycast 让“用户到底从哪个节点进来”变得不那么直观,排障时要结合路由表、边缘节点日志和回源日志一起看。

维度DNS 调度Anycast
调度依据解析结果、TTL、线路/地域策略BGP 路由选路
生效速度受 DNS 缓存影响路由收敛后较快
故障切换依赖解析和客户端重试路由撤销,新连接切换
成本相对低地址段、网络设备、运维成本高
主要风险缓存导致调度不即时路由优化复杂、长连接中断

两种方式可以组合使用:外层用 Anycast 承接大流量和就近接入,内层再用 DNS 做业务级灰度。组合之后,排障顺序要反过来:先确认用户落到哪个边缘节点,再看该节点的代理日志,最后才看规则命中。否则很容易在规则引擎里翻半天,最后发现请求根本没进 WAF。

3. 反向代理选型:为什么 WAF 的瓶颈常不在规则本身

WAF 作为反向代理时,是浏览器和源站之间的中间人。它要终结 TLS、解析 HTTP、维护连接池、处理请求头和请求体、做回源健康检查,再把响应流式返回。规则引擎只是其中一段 CPU 开销。实际线上更常见的瓶颈是:TLS 握手吃满 CPU、响应体缓冲导致内存上涨、同步日志拖慢 TTFB、正则回溯把单个 worker 卡死。选代理层时只看“规则多不多”会踩坑,代理层的事件模型和扩展方式决定了 WAF 能不能在业务流量下稳住。

常见的两类代理思路:一类是模块化、支持脚本扩展的代理,性能模型偏事件驱动,能利用多核,除了四层和七层代理还带基础 Web 服务和缓存能力;另一类是 ACL 能力强的代理,原生访问控制表达力好,转发性能稍高,官方支持后端健康检查。WAF 需要频繁读取 URI、参数、请求头、响应头,甚至响应体,所以扩展点是否足够细、脚本层是否能拿到标准化变量,比单纯看转发 benchmark 更重要。

3.1 事件驱动代理如何吃掉多核与 TLS 开销

事件驱动代理的核心是一个或多个事件循环:连接可读可写时触发回调,不在阻塞 I/O 上等。多核利用通常靠多进程或多线程,每个 worker 独立监听,连接按内核调度分到不同 worker。TLS 终结放在代理层后,源站可以卸掉证书开销,但代理层自己要承担握手、会话复用、证书链校验的成本。HTTP 解析器则决定请求头、分块传输、表单参数、multipart 上传能不能被稳定还原成规则引擎认识的变量。

WAF 规则真正吃 CPU 的地方通常有三处:正则匹配长字符串、多次解码转换、以及把大响应体当文本扫描。正则引擎在遇到带大量分支和量词的模式时可能回溯,URI 或参数越长,回溯路径越多,单个请求就能把 worker 占住;转换函数如果对每个变量都做 base64 解码、HTML 解码、去注释、压缩空白,等于把同一份内容反复复制;响应体如果先全量缓冲再扫描,内存会随并发上传和下载上涨。代理层如果支持流式过滤,就能在 body chunk 到达时边扫边放行,但流式扫描要处理跨 chunk 的关键字截断,不能简单按块匹配。

维度模块化脚本代理ACL 型代理
扩展方式脚本钩子、模块、缓存原生 ACL、后端健康检查
性能特点事件驱动,多核利用好转发性能稍高
WAF 适配阶段钩子细,能拿请求/响应变量ACL 表达强,复杂检测需外挂
主要风险脚本写不好会阻塞事件循环检测逻辑分散,规则维护成本高

这张表不是选型结论,而是提醒:WAF 的代理层选型要按检测位置倒推。如果只在访问阶段看 URI 和参数,ACL 型代理也能做;如果要看响应体、做 JSON 字段级检测、按内容类型分流,脚本钩子和流式过滤能力就更关键。

3.2 用 Lua 阶段钩子把检测插进请求生命周期

支持脚本扩展的代理通常把请求生命周期拆成多个阶段:TLS 证书处理、变量初始化、重写/重定向/缓存、访问阶段处理请求头、内容生成、响应头过滤、响应体过滤、日志异步记录。WAF 的主检测一般放在访问阶段,因为这时 URI、参数、请求头已经可读,且还没回源;响应体检测放在响应体过滤阶段,适合做敏感信息泄露、网页木马特征、响应头缺失检查;日志阶段只做异步落盘,不能在里面做重计算。

-- 伪代码:把 WAF 检测挂到访问阶段和响应体阶段 local function waf_on_access(ctx) local uri = ctx.var.request_uri or "" local args = ctx.var.args or "" local ua = ctx.var.http_user_agent or "" -- 先做长度限制,避免超长串进入正则和多次解码 if #uri + #args > 8192 then ctx.log("oversize_request", { uri_len = #uri, args_len = #args }) return ctx.exit(413) end local hit = rule_engine.match({ method = ctx.var.request_method, uri = uri, args = args, headers = ctx.headers, remote_addr = ctx.var.remote_addr }) if hit and hit.action == "DENY" then ctx.log("waf_deny", hit.rule_id) return ctx.exit(403) end end -- 响应体阶段只扫文本类型,二进制直接跳过 local function waf_on_body_chunk(ctx, chunk, eof) if not ctx.is_text_response then return chunk end rule_engine.scan_body(chunk) return chunk end

这段伪代码的关键不在语法,而在三个顺序:长度限制在规则匹配之前,避免长串把正则拖死;ctx.exit在命中拒绝动作时立即短路,不再回源;响应体阶段先判断内容类型,图片、压缩包、视频流不进入文本扫描。8192不是通用答案,要按业务 URI 和表单长度分布调;阈值太小会误伤正常长查询,太大则给回溯留空间。hit.action要区分DENY、PASS、REDIRECT,不能把所有命中都当阻断,否则观察模式没法用。

阶段钩子还有一个容易忽略的细节:响应体过滤可能被多次调用,chunk 边界会切断关键字。做流式检测时要保留一个滑动窗口,窗口大小至少覆盖最长特征串;如果业务允许,优先按 Content-Type 白名单只扫text/html、application/json这类文本响应,不要把 PDF、图片、压缩包拉进来。

注意:脚本钩子里不要做同步磁盘写、同步外部 HTTP 调用、大对象序列化。事件循环被阻塞一次,后面排队的所有连接都会看到延迟抖动,规则引擎的命中日志也会失真。

4. 规则引擎:正则匹配与语义识别如何拼成检测链

规则引擎要回答三个问题:看哪个变量、怎么把变量变成可匹配的形态、匹配后做什么动作。常见规则集以正则验证为主,覆盖已知漏洞特征,规则全面,能对上常见 Web 风险清单里的注入、跨站脚本、文件包含、命令执行等;语义识别则借助词法和语义库判断 SQL 注入、XSS 的变形写法,不要求规则穷举所有 payload。另一类思路是不依赖规则库,通过学习正常访问模式生成白名单式规则,用来发现未知威胁,但训练成本和误报控制是另一笔账。

规则引擎的选择不能只看“覆盖多少条”。正则规则集大约两百多条核心规则时,维护问题就开始出现:业务自定义参数一多,排除规则会膨胀;语义检测对编码、注释、空白变形的容忍度更好,但需要调阈值;自主学习方案对未知模式敏感,却容易把新上线的正常功能判成异常。实际系统往往是组合拳:正则兜底已知高危,语义检测处理变形注入,白名单和评分机制压误报。

4.1 动作、匹配条件与变量解析的执行模型

规则动作一般包括:PASS跳过当前阶段的后续规则,DENY阻断请求,ALLOW跳过所有检查,REDIRECT重定向,RESET_CONNECTION重置连接。动作的短路语义很重要:PASS只影响当前 phase,不是全局放行;ALLOW才是全局跳过。规则顺序如果写成先ALLOW再检测,等于把后面规则全部废掉;反过来,先DENY再ALLOW,白名单永远不生效。

匹配条件通常由变量组、解析方式、转换函数、操作函数和模式组成。变量组里常见的有请求方法、URL、请求 URI、参数集合、User-Agent、Referer、客户端地址、请求头集合、响应头集合、星期时间等。解析方式决定从变量里取哪一部分:指定某个 key、忽略某个 key、只取所有 key、只取所有 value、或者 key 和 value 全取。多个变量之间常见是“或”的关系,单个条件内的字段则按“与”组合;多个 match 条件之间的组合关系不同引擎可能不同,落地前要拿一条测试请求验证,不要凭直觉写。

-- 规则描述结构示意:动作、变量、解析、转换、操作符、模式 local rule = { id = "1001", phase = "access", action = "DENY", match = { { vars = { { var = "ARGS", parse = { values = true } }, { var = "REQUEST_URI" } }, transform = { "uri_decode", "lowercase", "compress_whitespace" }, operator = "detect_sqli", pattern = "", op_negated = false }, { vars = { { var = "HTTP_USER_AGENT" } }, transform = { "lowercase" }, operator = "contains", pattern = "scanner", op_negated = false } } }

id用于日志和灰度统计,phase决定规则在哪个阶段执行,action决定命中后的短路行为。vars里的ARGS配合parse.values = true表示取所有参数值;REQUEST_URI不带 parse 表示取整个 URI。transform按声明顺序执行,operator是最终判断函数,pattern是操作参数,语义检测类操作符可以不依赖 pattern。op_negated = true表示结果取反,适合做“不包含某特征才放行”的白名单规则,但取反规则最容易写出逻辑漏洞,灰度时要单独统计命中。

4.2 转换函数与操作函数的先后顺序

转换函数的作用是把变量还原成攻击者真正想表达的内容,常见有 URL 解码、HTML 解码、base64 解码、SQL 十六进制解码、去注释、去空字符、压缩空白、大小写转换、路径规范化、trim 等。操作函数则是判断动作,常见有前缀/后缀/包含、带词边界的包含、等于/大于/小于、数字范围、字符串范围、IP 段匹配、正则、URL 编码校验、SQL 注入检测、XSS 检测等。顺序错了,规则就会看起来写了但拦不住。

-- 同一变量上先解码再匹配,顺序不能反 transform = { "uri_decode", -- 先还原 %xx,避免编码绕过 "html_decode", -- 再还原实体字符 "remove_comments_char", -- 去掉 /*、*、--、# 等注释符 "compress_whitespace", -- 压缩空白,统一匹配视图 "lowercase" } operator = "regex" pattern = [[(?:^|[^a-z])(select|union|sleep)(?:[^a-z]|$)]]

这段配置先做 URI 解码,再做 HTML 解码,然后去掉注释符、压缩空白、转小写,最后用正则匹配关键字。顺序反过来的典型后果是:攻击者用%53%45%4C%45%43%54表示SELECT,规则先匹配原始串,正则看不到关键字;或者用sel/**/ect拆分,规则没去注释,语义检测也拿不到完整词。转换不是越多越好,remove_comments_char会删掉正常文本里的符号,html_decode对富文本业务容易误伤,所以高风险变量才上全套转换,普通展示字段用轻量转换加评分。

正则操作符要特别小心回溯。模式里少用无界量词嵌套,能锚定就锚定,能先长度限制就先限制;对长参数优先用contains、begins_with、ends_with这类线性判断,把正则留给短变量。语义检测操作符一般比大正则省规则维护成本,但它也有性能成本,不能对每个请求的所有参数无差别跑一遍。

4.3 规则集规模与未知威胁的取舍

规则集规模上去之后,真正难的是“规则生命周期”:新增规则怎么验证、误报怎么回滚、规则命中怎么归因、业务白名单怎么过期。大约两百多条核心规则听起来不多,但每条规则可能带多个变量、多个转换、多个匹配分支,实际执行路径远大于条数。规则热加载如果做成全量重建,重载瞬间会抖;如果做成增量编译,又要处理规则依赖和缓存失效。线上更稳的做法是分阶段:先旁路观察命中,灰度到小流量只记录不阻断,确认误报率后再切拦截。

未知威胁的取舍更明显。正则规则集对已知漏洞覆盖全面,但变形绕过依赖规则更新;语义识别对 SQL 注入、XSS 的编码和注释变形更稳,但对业务语义不理解,正常文本里出现敏感词也可能命中;自主学习方案能发现偏离正常模式的行为,却需要足够干净的训练流量,新功能上线、促销活动、客户端升级都会改变流量分布,误报会跟着涨。比较务实的组合是:高危动作直接阻断,可疑行为降级为挑战或记录,未知模式先观察再沉淀规则。

策略覆盖特点主要代价适用位置
正则规则集已知漏洞覆盖全,规则可解释规则维护和回溯成本兜底高危、明确特征
语义识别对编码、注释变形更稳阈值调参、误报治理注入类参数检测
自主学习对未知模式敏感训练流量要求高、误报波动观察模式、异常发现

规则引擎的“强”不体现在规则条数,而体现在命中之后能不能解释:命中了哪个变量、经过哪些转换、操作符返回什么、最终为什么阻断。日志里只有规则 ID 没有变量快照,误报排查就会变成黑匣子。

5. 避坑与排查:WAF 上线后最容易被误判的五种请求

WAF 上线后的第一周,最常见的不是“漏拦了多少攻击”,而是“正常业务被拦了”。误报排查不能靠猜规则,要按“请求重放、变量快照、规则命中、动作短路”四步走。下面五类现象是踩坑记录里出现频率较高的,处理思路比具体规则更重要。

5.1 现象:正常表单提交被 403

现象:用户提交带备注、地址、商品描述的表单,浏览器收到 403,接口日志里没有源站记录。原因:规则对参数值做了全套解码和去注释,正常文本里出现select、union、--这类词,或者转换顺序把 URL 编码还原后触发了正则;也可能是ALLOW白名单写在了DENY规则之后,短路顺序不对。解决:先用同一份请求体重放,打开规则命中日志,确认命中的变量和规则 ID;把该业务字段的转换降级为uri_decode + lowercase,去掉会破坏正常文本的remove_comments_char;白名单规则放在阶段最前面,并加过期时间,不要永久放行整个参数。

5.2 现象:图片上传被当成脚本拦截

现象:后台上传 JPG、PNG 正常,偶尔某些图片被拦,换一张图又好了。原因:响应体或请求体过滤把二进制当文本扫描,图片字节里恰好出现特征串;或者 multipart 解析后把文件内容拼进参数集合,正则对二进制做了匹配。解决:按 Content-Type 和文件头做白名单,图片、压缩包、音视频不进入文本规则;请求体检测只看表单字段,不看文件分片;如果必须扫文件内容,单独走病毒/木马检测链路,不要混在 SQL 注入和 XSS 规则里。

5.3 现象:移动端偶发拦截

现象:同一接口,桌面端正常,移动端小概率 403,日志里 User-Agent 各不相同。原因:规则对 User-Agent 做了contains或正则匹配,某些客户端版本号、渠道标识里带敏感词;或者移动网络经过代理,X-Forwarded-For和remote_addr取值不一致,IP 段规则误判。解决:User-Agent 规则只匹配明确的恶意特征,不要用宽泛单词;客户端信息取标准化后的真实 IP 链,代理层要明确信任哪些转发头;对渠道包和版本号做白名单,灰度期间按 UA 维度统计命中率,异常升高的规则先降级为观察。

5.4 现象:延迟突然升高

现象:接入 WAF 后 TTFB 从几十毫秒涨到几百毫秒,CPU 不高但请求排队,偶发超时。原因:正则在超长 URI 或参数上回溯;转换函数对每个参数重复解码;响应体全量缓冲后扫描,内存和 GC 压力上来;日志同步写盘拖慢事件循环。解决:先加长度限制和规则超时,再定位具体规则;用同一份请求重放,观察规则耗时和命中 ID;把非必要转换从全量变量移到高风险变量;响应体只扫文本类型并限制最大扫描长度;日志改异步批量写。

# 用同一份请求头重放,观察响应码、响应头和耗时 curl -v -o /dev/null -s \ -H 'User-Agent: test-client' \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data 'name=test&note=select%201' \ 'https://shop.example.com/search?q=test'

-v看响应头和状态码,--data模拟表单提交,%20是 URL 编码后的空格。重放时保留原始 Content-Type 和 User-Agent,否则命中的规则可能完全不同。排查延迟要在 WAF 边缘节点和源站两侧分别看时间:边缘耗时高,查规则和代理;回源耗时高,查源站和连接池。

5.5 现象:灰度后源站被直连绕过

现象:WAF 控制台显示攻击被拦,但源站日志里仍有大量直接请求;或者部分用户完全没经过 WAF。原因:CNAME 只切了主域名,子域名和旧客户端仍解析到源站;DNS 缓存未过期;源站安全组对公网开放,攻击者拿到源站 IP 后直连;健康检查地址和回源地址混在一起,没法只放行 WAF。解决:接入前盘点所有子域名、旧域名和客户端硬编码 IP;源站只接受 WAF 回源地址段,健康检查单独放行;DNS TTL 提前调低,灰度期间同时看 WAF 访问日志和源站访问日志,按请求 ID 对账;发现直连先收紧源站入口,再补接入,不要只加规则。

注意:源站隐藏不是接入 WAF 的副产物,而是独立的安全控制。只做 CNAME 不改源站入口,等于把 WAF 当成了可绕过的观察点。

6. 设计取舍:WAF 该放在哪一层、规则该收多紧

WAF 的形态选择本质上是把检测放在离应用多近的位置。本地硬件盒子串行部署延迟可控、数据不出本地,但扩容和运维重;旁路部署对业务影响小,却只能观察不能实时阻断;主机插件能拿到应用上下文,升级和性能隔离要小心;云 WAF 反向代理弹性好、接入快,但依赖 DNS/路由接入和回源控制,源站暴露风险要单独治理。没有一种形态适合所有业务,取舍点在于“能不能接受请求多一跳”和“能不能把源站入口收干净”。

形态部署位置优点主要代价适用场景
本地硬件盒子本地网络串行/旁路延迟可控、数据本地扩容慢、运维重固定机房、强本地化要求
主机插件嵌入 Web 服务器上下文细、接入快升级影响业务、性能隔离难单应用、快速补防
云反向代理边缘节点回源弹性、接入快、抗流量突增依赖接入、回源控制要求高公网业务、流量波动大

规则严格度也是取舍。全量拦截看起来安全,误报会把业务逼回关闭 WAF;全量观察看起来稳,攻击真发生时没有阻断。比较稳的路径是分级:高危动作直接DENY,可疑行为先PASS + 记录,未知模式进观察队列;每条新规则先旁路回放历史请求,再灰度小流量,最后才切拦截。验证时不要只看命中数,要看误报率、漏报样本、规则耗时和回源成功率,四个指标一起看才不容易被单点数据骗。

6.1 拦截模式与观察模式的验证习惯

观察模式不是“关掉 WAF”,而是把动作从阻断降级为记录,同时保留变量快照和规则 ID。灰度时按业务线、按 URL 前缀、按客户端类型分组,不要一次性全量。旁路回放可以用镜像流量或脱敏后的请求样本,重点看三类请求:正常业务里带特殊字符的、上传和多部分表单、以及移动端长 User-Agent。每类请求都要有基线,否则误报率没有分母。

6.2 一次教训换来的检查顺序

我早期接过一个接入项目,规则写得很全,上线后业务方反馈“偶尔提交失败”。排查时一直盯着规则内容,最后发现是 CNAME 只切了主域名,旧客户端仍解析到源站,WAF 日志里当然没有失败请求;同时源站安全组对公网开放,攻击流量绕过 WAF 直接打源站。从那以后我每次上线新规则,都强制先跑一遍旁路回放和灰度对比,再检查 DNS 覆盖、源站回源白名单、长连接重试,最后才看规则命中。规则可以慢慢调,接入层漏了,后面所有检测都是自我安慰。这份资料里的架构分层和规则字段表,我一般会对照着过一遍,避免只盯规则忘了流量第一跳。希望帮到你。

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

返回列表