【问题标题】:Nginx rewrite rule omit forward slash (/) when its first in encoded urlNginx 重写规则在编码 url 中的第一个时省略正斜杠 (/)
【发布时间】:2021-11-18 10:14:51
【问题描述】:

我正在尝试使用 Nginx (1.21.3) 重写,但不知何故,它在字符串中的第一个位置删除了 / 键。

重写规则:

#nginx not relevant conf here
location / {
    rewrite ^(.*)data/([0-9]+)/(.+)?$ $1processor.php?key=$2&data=$3 last;
}
#nginx not relevant conf here

当我对我测试过的任何 url 使用此重写规则时,一切正常。当我尝试像下面的示例这样的 url 时,它以某种方式在开头省略了 /

https://example.com/data/9/%2F*-%2B.%60!%40%23%24%25%5E%26*()_%2B%60-%3D%5B%5D%3B%27%5C%2C.%2F%7B%7D%3A%22%7C%3C%3E%3F

当我用通知重新加载 nginxrewrite_log=on; 时,我得到了输出:

2021/09/25 13:08:29 [notice] 528#528: *11710 "^(.*)data/([0-9]+)/(.+)?$" matches "/data/199/*-+.`!@#$%^&*()_+`-=[];'\,./{}:"|<>?", client: 192.168.255.107, server: localhost, request: "GET /data/199/%2F%2A-%2B.%60%21%40%23%24%25%5E%26%2A%28%29_%2B%60-%3D%5B%5D%3B%27%5C%2C.%2F%7B%7D%3A%22%7C%3C%3E%3F HTTP/2.0", host: "example.com", referrer: "https://example.com/"

PHP (8.0.10) $_GET["data"] 输出是(如您所见,没有/,因此不是精确的数学):

*-+.`!@#$%^&*()_+`-=[];'\,./{}:"|<>?

我该如何解决?

【问题讨论】:

标签: php regex nginx pcre


【解决方案1】:

rewritelocation 指令都适用于所谓的 normalized URI:

在对以“%XX”形式编码的文本进行解码后,对规范化的 URI 执行匹配,解析对相对路径组件“.”的引用。和“..”,可能会将两个或多个相邻的斜线压缩成一个斜线

这意味着在第一阶段你的 URL /data/9/%2F*-%2B.%60!%40%23%24%25%5E%26*()_%2B%60-%3D%5B%5D%3B%27%5C%2C.%2F%7B%7D%3A%22%7C%3C%3E%3F 得到 URL 解码:

/data/9//*-+.`!@#$%^&*()_+`-=[];'\,./{}:"|<>?

在第二阶段,两个相邻的斜线被压缩成一个:

/data/9/*-+.`!@#$%^&*()_+`-=[];'\,./{}:"|<>?

上面的字符串确实需要测试rewrite 指令,从而导致丢失第一个 URL 编码的斜杠。但是,您可以使用 $request_uri 变量,其中包含未修改形式的请求 URI。您可以使用任一

if ($request_uri ~ ^(?<prefix>.*/)data/(?<key>\d+)/(?<data>[^?]+)) {
    rewrite ^ ${prefix}processor.php?key=$key&data=$data;
}

块放置在服务器上下文或

location /
    if ($request_uri ~ ^(?<prefix>.*/)data/(?<key>\d+)/(?<data>[^?]+)) {
        rewrite ^ ${prefix}processor.php?key=$key&data=$data last;
    }
    ...
}

块放置在位置上下文中。

【讨论】:

  • 非常感谢 Ivan,您对使用 merge_slashes = off 有何看法?
  • 我宁愿不要。它也应该可以工作,但可能会有一些caveats请注意,压缩对于正确匹配前缀字符串和正则表达式位置至关重要。没有它,//scripts/one.php 请求将与location /scripts/ { ... } 不匹配,并且可能被作为静态文件处理。所以它被转换为/scripts/one.php
猜你喜欢
  • 2016-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-13
  • 1970-01-01
  • 2015-01-27
  • 2014-01-17
  • 2016-03-30
相关资源
最近更新 更多