Nginx server块中SQL注入过滤本质是关键词粗筛,仅基于已解码的$args和原始编码的$request_uri做正则匹配并return 403阻断,不解析SQL语义、不读取$request_body。

在 Nginx 的 server 块中过滤 SQL 注入,本质是做**关键词粗筛**——它不解析 SQL 语义,也不读取 POST 请求体,只对 URL 路径和查询参数($request_uri 和 $args)中的明文攻击特征做正则匹配,并立即阻断。这是最外层、轻量但有效的第一道防线。
只用两个变量:$args 和 $request_uri
必须明确:
• $args 是已解码的查询字符串(如 id=1%20or%201=1 → 匹配为 id=1 or 1=1)
• $request_uri 是原始 URI(含编码,如 /api?id=1%20union%20select → 需匹配 %20union%20select 或 union[[:space:]]+select)
• $request_body 在标准配置下为空,不能用于 if 判断,否则规则完全失效
推荐的拦截规则写法(放 server 块内)
用 return 403 终止请求,避免用 rewrite,防止被重定向绕过:
if ($args ~* "(%27)|(')|(--)|(%23)|(#)|\b(select|union|insert|update|delete|drop|exec|declare)\b") { return 403; }if ($request_uri ~* "(%20OR%20|%20AND%20|/\*|\*/|;\s*(select|union)\s+from)") { return 403; }
关键细节:
• \b 保证单词边界,避免误伤 user_id、comment 等正常字段
• 匹配 %20OR%20 比单纯 OR 更可靠,因空格常被 URL 编码
• 不匹配 order by、limit 等合法关键词,减少误杀
必须避开的常见错误
这些配置会让规则形同虚设:
- 把
if写在http{}块顶层——Nginx 不允许,会报错或不生效 - 在
location ~ \.php$里写规则,却用 raw 字符去匹配已解码的$args - 正则中漏转义特殊字符,比如点号
.、括号(),导致实际未匹配 - 用
rewrite ... break替代return 403,攻击者可构造跳转绕过
比 Nginx 规则更关键的防护动作
Nginx 层面的拦截只是辅助,真正防住 SQL 注入靠的是应用层加固:
- PHP 全部使用 PDO 预处理 +
bindValue(),杜绝字符串拼接 SQL - MySQL 创建专用账号,只授予必要权限(如仅
SELECT、INSERT),禁用DROP、EXEC - 禁用 PHP 危险函数:
eval()、system()、exec()、passthru()
不复杂但容易忽略











