nginx的location不匹配query string,需用$request_uri或$query_string配合if拦截;例如拦截“?http”用if ($request_uri ~ "^/\?http") { return 403; },禁止末尾孤立?用if ($request_uri ~ "?$") { return 400; }。

在 Nginx 的 location 配置中,location 本身不匹配 query string(即问号 ? 后的部分)。这是关键前提:无论你写 location /api 还是 location = /api?token=123,Nginx 都会忽略 ?token=123,只按 /api 匹配路径。所以想“在 location 中直接带问号匹配”,语法上无效,也永远不会命中。
用 $request_uri 或 $query_string 变量做条件拦截
要真正识别并拦截含特定参数的请求,必须借助 if 指令配合内置变量:
-
$request_uri:原始未解码的完整请求串,含路径 + ? + 参数,例如
/search?q=nginx&page=1 -
$query_string:仅 query string 部分(不含 ?),已解码,例如
q=nginx&page=1
推荐优先用 $request_uri,它保留编码信息,能准确捕获如 %3F、%26 等绕过手段。
示例:拦截所有带 ?http 开头的恶意参数
location / {
if ($request_uri ~* "^/\?http") {
return 403;
}
}
精准拦截某路径 + 特定参数组合
如果只想封禁某个接口的特定参数(比如禁止 /chatIndex 带 kefu_id=l5702123&ent_id=324),不要用 location 路径匹配,而是用正则锁定整个 URI 模式:
location /chatIndex {
if ($query_string ~* "^kefu_id=l5702123&ent_id=324$") {
return 403;
}
# 其他正常处理,如 proxy_pass
proxy_pass http://backend;
}
注意:^ 和 $ 保证参数完全匹配,避免误伤 kefu_id=l57021234 这类相似值。
统一过滤非法或冗余问号行为
有些攻击会在 URL 末尾加空参数(如 /index.html?)或重复问号(/api??v=1),可用以下规则清理:
- 拒绝末尾带孤立
?的请求:if ($request_uri ~* "\?$") { return 400; } - 拒绝双问号或
?#类混淆:if ($request_uri ~* "\?\?|\?#") { return 400; } - 拒绝含 URL 编码问号(
%3F)的非常规参数:if ($request_uri ~* "%3F") { return 403; }
不建议的做法和风险提示
以下方式不可靠或存在隐患:
- 在
location中写location /path?xxx—— 语法错误,Nginx 启动失败 - 仅依赖
$uri判断参数 ——$uri不含 query string,永远为空,无法用于参数拦截 - 在多个
if块中嵌套判断 ——if在 location 内部有执行限制,且嵌套易出错;应合并为单条正则 - 滥用
if做复杂逻辑 —— Nginx 官方明确说明if性能低、语义易歧义,仅适合简单条件拦截











