通过日志中403、444、499状态码可快速识别WAF拦截请求:403表示明确拒绝,444为Nginx主动关闭连接,499多因客户端超时断开;结合$request和$args字段分析攻击指纹,如SQL注入、XSS等特征;再聚合高频IP+路径+参数组合定位真实攻击;最后通过自定义日志标记(如$waf_reason或ngx.log)明确拦截规则来源。

直接看日志里返回状态码和请求字段,就能快速识别哪些请求被 WAF 拦截了。
重点查 403、444、499 这三类状态码
Web 防火墙拦截后,Nginx 通常不会让请求到达后端,而是主动终止连接或返回拒绝响应:
- 403 Forbidden:最常见,说明规则匹配成功并明确拒绝,比如 UA 黑名单、SQL 关键字命中、Referer 非法等;
- 444 No Response:Nginx 主动关闭连接,不发任何响应(如拦截 sqlmap、nikto 等扫描器时常用),日志中会显示 “-” 代替响应体大小和响应时间;
- 499 Client Closed Request:客户端在收到响应前断开(常出现在 Lua WAF 主动限流/挑战失败后重定向超时,或 CC 防御触发连接丢弃)。
结合 $request 和 $args 字段分析攻击指纹
光看状态码不够,要定位“为什么被拦”,得看原始请求内容:
- 在 log_format 中确保已记录 $request(含方法、路径、协议)和 $args(完整查询参数),例如:
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $args'; - 典型攻击特征会直接暴露在 $args 或 $request_uri 中,比如:
•/login?username=admin' OR '1'='1&password=123→ SQL 注入
•/search?q=<script>alert(1)</script>→ XSS
•/api/v1/user?id=1%20UNION%20SELECT%20@@version→ 编码绕过检测
关注高频出现的 IP + 特征组合
真实攻击往往批量发生,单条日志难判断,需横向比对:
- 用 awk/grep/awk 快速聚合:比如
awk '$9 ~ /403/ {print $1,$7,$12}' access.log | sort | uniq -c | sort -nr | head -20,查看哪些 IP 对哪些路径+参数组合反复触发 403; - 若某 IP 在 1 分钟内对 /login 发起 50 次带
password=的 POST,且 User-Agent 是空或 python-requests,基本可判定为暴力破解; - 若多个不同 IP 都携带
eval(、base64_decode、phpinfo等字符串访问任意 .php 路径,大概率是自动化漏洞扫描。
配合自定义日志标记识别规则来源
如果用了 if 判断或 Lua 模块做拦截,建议在日志中显式打标:
- 在配置中用 map 定义拦截原因:
map $block_reason $waf_reason { default "-"; "sql" "SQLi"; "xss" "XSS"; "ua_bad" "BadUA"; }
再把 $waf_reason 加进 log_format,每条拦截日志末尾就带上了具体规则类型; - OpenResty 用户可在 access_by_lua_block 中调用 ngx.log(ngx.WARN, "blocked: SQLi from ", ngx.var.remote_addr),同时写入 error.log,便于与 access.log 关联排查。











