适用场景
网站经常被扫描器、爬虫和自动化脚本骚扰:日志中出现大量 curl、sqlmap、python-requests 等 User-Agent(UA)特征的高频请求,挤占带宽、消耗应用资源,甚至成为漏洞探测的前奏。本方案通过 Nginx 的 UA 黑名单机制,在接入层直接拦截恶意 User-Agent 请求,适合部署在面向公网的 Nginx 服务器、反向代理或负载均衡器上,也适合 WordPress、企业官网等站点的第一道访问防线。
前置条件
- Linux 服务器(本文以 Ubuntu/Debian 为例),已安装 Nginx 1.18 或更高版本
- 对
/etc/nginx/目录有读写权限,且会执行nginx -t测试与systemctl reload nginx重载 - 已配置好站点 server 块(如
/etc/nginx/sites-available/wafai.conf)
原理说明
UA 黑名单的拦截思路是:根据 HTTP 请求头 User-Agent 的取值特征匹配已知恶意工具,命中后直接返回 403。Nginx 在 http 上下文用 map 指令把 UA 映射为标记变量,再到 server/location 中用 if 判断拦截。相比在应用层(PHP/Python)拦截,Nginx 层拦截发生在最前端,不消耗业务进程资源,且支持正则、忽略大小写,配置一次全局生效。
需要说明的是:UA 是可以伪造的,黑名单属于「提高攻击成本」的纵深防御手段,应与其他防护(限频、WAF、日志溯源)组合使用,不能作为唯一防线。
操作步骤
1. 创建独立 UA 黑名单配置文件
为便于维护,把映射规则独立成文件:
sudo mkdir -p /etc/nginx/conf.d
sudo nano /etc/nginx/conf.d/block_ua.conf
写入以下内容(按工具类型分组,全部使用 ~* 忽略大小写匹配):
# 常见命令行工具与下载器
map $http_user_agent $bad_bot {
default 0;
~*curl 1;
~*wget 1;
~*libwww-perl 1;
~*Go-http-client 1;
~*Java/ 1;
~*okhttp 1;
# 漏洞扫描器
~*sqlmap 1;
~*nikto 1;
~*nmap 1;
~*masscan 1;
~*zgrab 1;
~*acunetix 1;
~*nessus 1;
~*fimap 1;
# 爬虫与采集器
~*scrapy 1;
~*python-requests 1;
~*aiohttp 1;
~*urllib 1;
~*HTTrack 1;
~*offline\ explorer 1;
~*semrushbot 1;
# 目录枚举与漏洞利用工具
~*dirbuster 1;
~*dirb 1;
~*gobuster 1;
~*wpscan 1;
}
2. 在主配置中引入 map
编辑 /etc/nginx/nginx.conf,在 http { } 块内(必须位于 server 块之前)加入:
http {
include /etc/nginx/conf.d/block_ua.conf;
# ... 其余配置
}
3. 在 server 中启用拦截
编辑站点配置,在 server 块顶部加入:
server {
listen 443 ssl;
server_name www.wafai.cn;
# UA 黑名单:命中直接 403
if ($bad_bot) {
return 403;
}
# 其他配置...
}
4. 对放行工具限频兜底(可选)
若某些工具 UA 无法精确区分(如泛化的 python-requests),可对可疑 UA 应用限频而不是直接拦截:
map $http_user_agent $suspicious_bot {
default 0;
~*(python-requests|aiohttp|curl) 1;
}
# 在 server 内:
limit_req_zone $binary_remote_addr zone=bot_limit:10m rate=5r/m;
server {
if ($suspicious_bot) {
limit_req zone=bot_limit burst=10 nodelay;
}
}
注意:limit_req_zone 需放在 http 上下文;limit_req 放在 location 内更安全,放在 server 的 if 中仅用于演示。
配置验证
# 1. 语法检查
sudo nginx -t
# 2. 重载配置
sudo systemctl reload nginx
# 3. 模拟恶意 UA,应返回 403
curl -A "sqlmap/1.8.2" -I https://www.wafai.cn/
# 期望输出:HTTP/1.1 403 Forbidden
# 4. 模拟正常浏览器 UA,应返回 200
curl -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/126.0" -I https://www.wafai.cn/
# 期望输出:HTTP/1.1 200 OK
进阶验证:用真实扫描器测试并查看 access.log,确认命中请求返回 403:
grep "403" /var/log/nginx/access.log | tail -n 20
常见问题
FAQ 1:为什么拦截了 curl 后,我自己用 curl 测试也进不来了?
这是预期的。黑名单规则同样作用于你的测试请求。建议:给运维测试机器单独维护一份「白名单放行」规则,或使用浏览器/带自定义 UA 的工具测试,例如 curl -A "Mozilla/5.0 Test" https://www.wafai.cn/。生产环境应避免把 curl、wget 整体拦截过严,必要时改为限频而非 403。
FAQ 2:攻击者改了 UA 就绕过,UA 黑名单还有意义吗?
有意义。绝大多数批量扫描和自动化攻击直接使用默认 UA,不会逐一伪造;UA 黑名单能过滤掉约 60%-80% 的无差别流量。对伪造 UA 的高级攻击,需要配合限频(limit_req)、行为分析(请求速率、路径模式)和 WAF 规则进一步拦截。UA 黑名单是纵深防御的第一层,不是唯一层。
总结
本文通过 map + if 在 Nginx 接入层实现了恶意 UA 黑名单拦截:独立配置文件便于维护,正则匹配覆盖常见扫描器与爬虫,返回 403 不消耗业务资源,并可用限频兜底。配置要点:map 必须放在 http 上下文且先于 server 定义;匹配一律忽略大小写;先 nginx -t 再重载。建议将 UA 黑名单与限频配置、WAF 规则组合,形成「UA 拦截 + 速率限制 + 行为分析」三层防护,同时保留 access.log 用于后续溯源。