Nginx可通过组合配置实现非法请求的精准拦截与可追溯日志记录:先用map预判并标记请求类型,再通过条件access_log和return分层拦截,将不同非法类型写入独立日志,并配合error_log与Fail2ban自动封禁。

Nginx 本身不主动“记录非法请求的详情”,但可通过组合配置实现精准拦截 + 可追溯日志记录,关键在于:先拦截、再打标、最后落日志,避免无效请求污染主访问日志,同时保留审计线索。
拦截前先做分类标记,让日志可区分
直接在 location 或 server 块中用 map 指令预判请求合法性,生成自定义变量(如 $blocked_reason),后续可在日志格式中引用:
map $request_uri $blocked_uri {
~* \.(git|env|ini|bak|sh|py)$ "sensitive_ext";
~* "(\?|&)(cmd|exec|debug|file|path)=|\.%2e|%2e%2e" "dangerous_param";
~* ^/\. "dot_path";
default "";
}
map $host $blocked_host {
~*^[^a-zA-Z0-9.-]$ "invalid_host";
"" "missing_host";
default "";
}
log_format blocked '[$time_local] $remote_addr "$request" $status "$http_referer" "$http_user_agent" blocked="$blocked_uri$blocked_host"';
access_log /var/log/nginx/blocked.log blocked if=$blocked_uri;
access_log /var/log/nginx/blocked.log blocked if=$blocked_host;这样,只有被判定为非法的请求才会写入 blocked.log,且每条日志自带拦截原因(如 blocked="sensitive_ext"),便于归因分析。
针对不同非法类型,用 return + 日志分离
不要把所有拦截都塞进一个 if 里。按风险等级和来源分层处理,每类单独打日志:
-
敏感路径请求(如
/.env,/admin.php)
用location精确匹配,立即return 403,并启用独立日志:location ~ /\. { access_log /var/log/nginx/dotfile.log main; return 403; } -
非法 Host 头或 IP 直连
在default_server中拦截,同时记录:server { listen 80 default_server; server_name _; access_log /var/log/nginx/host_spoof.log main; return 403; } -
含高危参数的静态资源请求
在静态资源location内校验$args,失败即拦:location ~* \.(js|css|png|jpg|gif)$ { if ($args ~* "(cmd|file|debug)=|(\.\.|%2e)") { access_log /var/log/nginx/bad_param.log main; return 400; } try_files $uri =404; }
⚠️ 注意:
if在location内可用,但不能嵌套;return后语句不再执行,确保它在逻辑末尾或唯一出口。
配合 Fail2ban 实现自动封禁与日志联动
Nginx 日志是 Fail2ban 的输入源。只需让非法行为在日志中留下稳定、唯一、易匹配的字符串,Fail2ban 就能自动提取 IP 并调用防火墙:
例如,在拦截规则中统一加一句 error_log 记录(比 access_log 更轻量,且 Fail2ban 默认扫描 error.log):
if ($blocked_uri) {
error_log /var/log/nginx/error.log warn;
return 400;
}然后 Fail2ban 规则可匹配:
failregex = ^.*\[warn\].*blocking.*$
再配合 bantime 和 maxretry,实现从单次拦截 → 频次统计 → 自动封禁的闭环。
关键细节不能漏
-
access_log ... if=是 Nginx 1.7.0+ 支持的条件日志,必须用变量判断,不能写if ($args) { access_log ... }(语法错误) - 所有拦截
return前,确保access_log或error_log已声明,否则无记录 - 避免在
http块顶层写if,应限定在server或location内作用域 - 日志路径需确保 Nginx 用户(如
www-data)有写权限,否则静默失败
不复杂但容易忽略


















