nginx通过geo模块标记恶意ip段、map匹配user-agent/referer特征及args/uri注入关键词,在解析阶段双重过滤并返回403阻断sql注入扫描。

直接在 Nginx 配置中拦截 SQL 注入扫描源,核心不是等请求进后端,而是在解析阶段就识别并阻断——重点是结合 IP 行为特征与请求内容特征做双重过滤。
用 geo 模块标记高危扫描 IP 段
很多 SQL 注入扫描器(如 sqlmap、Acunetix)来自固定云平台或已知恶意网段。可预先将这些 IP 段加入黑名单:
- 在 http 块顶部添加:
geo $is_scan_ip {<br> default 0;<br> 185.192.124.0/22 1;<br> 167.94.138.0/24 1;<br> ~^195\.154\.1[0-9]{2}\. 1;<br>} - 后续用
if ($is_scan_ip) { return 403; }统一拦截 - 注意:geo 匹配优先于 location,且支持 CIDR 和正则写法,适合匹配动态段
基于 User-Agent 和 Referer 识别扫描工具
多数自动化扫描器会暴露特征,Nginx 可在路由前识别并拒绝:
- 定义识别规则:
map $http_user_agent $is_scanner {<br> default 0;<br> ~*sqlmap|nikto|wvs|acunetix|webinspect 1;<br> ~*Mozilla.*ZmEu 1;<br>} - 补充 Referer 判断(空 Referer 或含 scan/test 字样):
map $http_referer $is_suspicious_ref {<br> default 0;<br> "" 1;<br> ~*scan|test|poc|exploit 1;<br>} - 统一拦截:
if ($is_scanner = 1) { return 403; }<br>if ($is_suspicious_ref = 1) { return 403; }
拦截含注入特征的请求参数与路径
扫描器常批量发送带关键字的请求,需覆盖 URL 编码、大小写、空格变体:
- 用
map提取风险信号(更清晰、性能更好):map $args $has_inject_arg {<br> default 0;<br> ~*(?i)(union\s+select|select\s+.*\s+from|exec\s+xp_|load_file|sleep\(|benchmark\() 1;<br> ~*[\"';`]|(--)|(%23)|(#)|(%27)|(%22) 1;<br>} - 同时检查 URI 中的路径穿越和敏感路径:
map $request_uri $uri_risk {<br> default 0;<br> ~*\.\./|/etc/passwd|/phpmyadmin|/wp-admin 1;<br> ~*(%3C|%3E|<script>}</script> - 在 server 或 location 中启用:
if ($has_inject_arg = 1) { return 403; }<br>if ($uri_risk = 1) { return 403; }
配合限流机制压制高频探测行为
单个 IP 短时间大量发包本身就是扫描信号,应叠加毫秒级限流:
- 定义限流区:
limit_req_zone $binary_remote_addr zone=sqlscan:10m rate=3r/s; - 对通用入口(如 /api、/index.php)启用:
location ~ \.php$ {<br> limit_req zone=sqlscan burst=5 nodelay;<br> # 后续 proxy_pass 或 fastcgi_pass<br>} - 超限后返回 503,避免暴露真实响应,也降低后端压力











