最稳妥方式是在http块用map预定义$blocked_ua变量匹配可疑UA,再在server块顶层用if($blocked_ua) return 403;避免在location内直接if正则,以防被proxy_pass等跳过或引发502。

在 Nginx 中拒绝特定 User-Agent(UA)访问,最稳妥、可维护且兼容性好的方式是用 map + if 组合:在 http 块中预定义 UA 匹配逻辑,再在 server 块顶层统一拦截并返回 403。不建议直接在 location 内写 if 判断 UA,容易被 try_files 或 fastcgi_pass 绕过,还可能引发 502 错误。
在 http 块中统一定义 UA 拦截规则
把所有 UA 匹配逻辑集中写在 http 块顶层,性能高、易管理、支持大小写不敏感和正则:
- 复制以下配置到
nginx.conf的http { ... }区域内(注意缩进与分号):
default 0;
~* (sqlmap|nikto|gobuster|nuclei|acunetix|whatweb|zmap|masscan) 1;
~* (python-requests|curl|wget|httpie|Go-http-client) 1;
~* (scanner|crawler|exploit|pentest|vuln|hack) 1;
~* (^$|^\s*$|^-$) 1;
~* Sogou\ web\ spider 0; <!-- 白名单示例,放最后 -->
}
-
~*表示不区分大小写的正则匹配 - 空 UA、纯空白、短横线(
-)等边缘情况都被覆盖 - 白名单必须显式设为
0,且写在黑名单之后(map按顺序匹配,第一条命中即生效)
在 server 块中触发拦截
进入对应站点的 server 块,在 location / 之前添加判断语句:
- 写法简洁安全:
if ($blocked_ua) {
return 403 "Access denied.";
} - 返回带提示的 403,比空响应更利于日志识别,又不泄露后端细节
- 不要嵌套在
location内——避免被代理或重写逻辑跳过
增强防御效果的实用补充
单靠 UA 拦截不够,建议同步做三件事:
-
记录 UA 和拦截状态:修改
log_format,加入$http_user_agent $blocked_ua,方便排查 -
对高频触发者限流:提前定义
limit_req_zone $binary_remote_addr zone=ua_block:10m rate=1r/s;,再在 server 中加limit_req zone=ua_block burst=5 nodelay; -
路径级强化:若某 UA 集中扫
/admin或/wp-login.php,可用location ^~ /admin单独加严规则,不依赖全局 UA 判断
验证与上线前必做
每次修改后务必执行:
-
nginx -t:检查语法是否正确 -
nginx -s reload:热加载配置 - 用
curl -H "User-Agent: sqlmap/1.7" https://yoursite.com/测试是否返回 403


















