nginx动态拼接第三方跳转地址需正确使用$arg_*等变量、优先return 302而非rewrite、严格校验$arg_target防开放重定向,并用map预处理多条件路由以保障安全与可维护性。

在 Nginx 中使用 rewrite 模块配合变量动态拼装第三方跳转地址,核心在于正确引用内置变量、合理控制重写时机(last / redirect)、避免循环和编码问题。这不是简单拼字符串,而是要兼顾 URL 安全性、参数完整性与 Nginx 的执行阶段。
用 $arg_* 和 $query_string 获取原始参数
Nginx 变量是动态拼接的基础。若请求是 /jump?target=pay.example.com&uid=123&sig=abc,想跳转到 https://pay.example.com/pay?uid=123&sig=abc,不能硬编码,得提取参数:
-
$arg_target直接取target参数值(自动解码) -
$arg_uid、$arg_sig分别取对应参数 - 若需保留全部原始查询参数(含未命名的),可用
$query_string,但要注意它包含完整 query,需剔除target=...部分,否则会重复
用 rewrite + return 302 实现安全跳转
推荐优先用 return 302 替代 rewrite ... redirect,更清晰、不触发 location 重匹配,避免意外循环:
- 例如:
return 302 https://$arg_target/pay?$args;—— 这里$args是 Nginx 自动拼好的、已编码的查询串(不含问号),比手动拼$arg_uid=&$arg_sig=更可靠 - 如果目标域名需白名单校验,先用
map做映射或正则匹配,再决定是否放行,防止开放重定向漏洞 - 对
$arg_target做基础校验(如只允许字母、数字、点、连字符),可用if ($arg_target ~* ^[a-z0-9.-]+\.[a-z]{2,}$) { ... },但注意if在 location 中才安全
处理特殊字符和编码一致性
用户传来的参数可能含空格、中文、斜杠等,Nginx 默认会对 $args 和 $uri 做转义,但 $arg_* 是解码后的值。拼接时容易出错:
- 不要用
$arg_target直接拼 URL 路径部分(如https://$arg_target/path),因为若参数里含%2F,解码后变成/,可能破坏结构 - 若必须保留原始编码,改用
$args整体或通过map+set配合perl或 Lua 模块(不推荐纯原生方案) - 常见做法:对目标 host 单独校验,路径和参数用固定结构拼接,避免把不可信输入直接嵌入 host 或 path
结合 map 做多条件路由与变量预处理
当跳转逻辑复杂(比如不同 target 对应不同路径、不同参数映射),用 map 提前定义规则,比一堆 if 更高效、更易维护:
- 在
http块中定义:map $arg_target $upstream_host { default "fallback.example.com"; "pay.example.com" "pay.example.com"; "api.example.net" "api-v2.example.net"; } - 再用
set $jump_url "https://$upstream_host/proc?uid=$arg_uid&ts=$time_iso8601";预拼 URL - 最后
return 302 $jump_url;—— 注意这里变量已展开,Nginx 会自动编码特殊字符
不复杂但容易忽略细节:变量作用域、编码层级、重定向状态码选择、以及最重要的——永远校验外部输入。直接拼接未经校验的 $arg_* 到跳转地址,等于给攻击者开了一扇重定向门。











