Nginx重写规则403错误

Adr*_*ian 3 rewrite nginx .htaccess

我在将 .htaccess 文件转换为 nginx 时遇到问题。我有 3 个 .htaccess 文件。第一个 .htaccess 文件位于文档根目录中,如下所示:

Options +FollowSymLinks
RewriteEngine On
RewriteRule ^img-(.*)\.html img.php?id=$1 [L]
RewriteRule ^slide-(.*)\.html slider.php?id=$1 [L]
RewriteRule ^page-(.*)\.html page.php?name=$1 [L]
RewriteRule ^contact\.html$ contact.php [QSA,L,NC]
Run Code Online (Sandbox Code Playgroud)

第二个 .htaccess 文件位于名为 upload 的文件夹中:

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^http://(.+\.)?foo\.com/ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteRule .*\.(jpe?g|gif|bmp|png)$ nohotlink.gif [L]
<Files ~ "\.(php|sql|php3|php4|phtml|pl|py|jsp|asp|htm|shtml|sh|cgi)$">
  order allow,deny
  deny from all
</Files>
Run Code Online (Sandbox Code Playgroud)

第三个也是最后一个 .htaccess 文件位于名为“small”的上传文件夹的子目录中:

RewriteEngine Off
Run Code Online (Sandbox Code Playgroud)

现在我在 /etc/nginx 中创建了一个文件夹,名为 includes 并使用这些重写规则制作了 3 个单独的 .access 文件:

对于位于文档根目录中的第一个 .htaccess 文件,我在 /etc/nginx/includes 中创建了一个名为 root.access 的文件。在这个文件中,我有:

# nginx configuration 

location /img { 
rewrite ^/img-(.*)\.html /img.php?id=$1 break; 
} 
location /slide { 
    rewrite ^/slide-(.*)\.html /slider.php?id=$1 break; 
} 
location /page { 
    rewrite ^/page-(.*)\.html /page.php?name=$1 break; 
} 
location /contact { 
    rewrite ^/contact\.html$ /contact.php break; 
}
Run Code Online (Sandbox Code Playgroud)

对于位于“upload”文件夹中的第二个文件,我在 /etc/nginx/includes 中创建了一个名为 upload.access 的文件。该文件包含以下内容:

# nginx configuration 

location /upload { 
if ($http_referer !~ "^http://(.+\.)?foo\.com/"){ 
rewrite .*\.(jpe?g|gif|bmp|png)$ /nohotlink.gif break; 
} 
} 
location ~ \.(php|sql|php3|php4|phtml|pl|py|jsp|asp|htm|shtml|sh|cgi)$ { 
deny all; 
}
Run Code Online (Sandbox Code Playgroud)

对于第三个也是最后一个文件,我在 /etc/nginx/includes names small.access 中创建了一个文件。该文件的内容如下:

# nginx configuration 

location /upload/small { 
}
Run Code Online (Sandbox Code Playgroud)

在服务器块配置文件中,我有:

 location / {
              try_files $uri $uri/ /index.php;
              include /etc/nginx/includes/root.access;
     }

 location /upload {
              include /etc/nginx/includes/upload.access;
     }

 location /upload/small {
              include /etc/nginx/includes/small.access;
     }
Run Code Online (Sandbox Code Playgroud)

现在使用此配置尝试该站点时,我收到 403 错误。Nginx 错误日志报告:

[error] 18156#0: *7 access forbidden by rule, client: 111.**.**.**, server: foo.com, request: "POST /upload.php HTTP/1.1", host: "foo.com", referrer: "http://foo.com/"
Run Code Online (Sandbox Code Playgroud)

现在在 apache 下一切正常。但我不明白为什么我会收到 403 错误。我也担心我所说的重写规则,除了 403 错误之外,根本无法正常运行。谁能帮我这个?我看不出这里有什么问题。

Xav*_*cas 10

这是这部分配置的标准 nginx 行为:

location /upload { 

    if ($http_referer !~ "^http://(.+\.)?foo\.com/"){ 
        rewrite .*\.(jpe?g|gif|bmp|png)$ /nohotlink.gif break; 
    } 

    location ~ \.(php|sql|php3|php4|phtml|pl|py|jsp|asp|htm|shtml|sh|cgi)$ { 
        deny all; 
    }

}
Run Code Online (Sandbox Code Playgroud)

为什么?

让我澄清一下位置是如何工作的:当 nginx 读取配置文件时,它会将位置块排序为 3 种类型:

  • 确切的位置块,例如location = /upload { }
  • 前缀位置块,例如location /upload { }
  • 包含正则表达式的位置块,例如location ~ /upload { }

一旦请求来到nginx,位置选择过程如下:

  1. 如果找到与 URI 匹配的确切位置块,nginx 将停止搜索其他位置块并提供此请求。
  2. 如果没有,nginx 将搜索最长匹配的前缀位置块并记住它,然后再进行下一步。
  3. 然后 nginx 依次检查包含正则表达式的位置块。第一个匹配的将用于服务请求。
  4. 如果在上一步没有找到任何东西,那么 nginx 将使用第 2 步的前缀位置块来服务请求。如果没有找到,可能会发生几件事,但这是题外话。

因此,在您的情况下,与.php扩展名匹配的位置块优先于/upload与 URI 部分匹配的位置块。

编辑:澄清解决方案,添加了替代解决方案。

使用^~你可以告诉 nginx 改变他在第 2 步的行为,这样它就会立即使用匹配的前缀位置,绕过正则表达式位置查找。所以你有两个解决方案:

解决方案1

上传访问:

if ($http_referer !~ '^http://(.+\.)?foo\.com/') { 
    rewrite '.*\.(jpe?g|gif|bmp|png)$' '/upload/nohotlink.gif' break; 
} 

if ($uri ~ '\.(php|sql|php3|php4|phtml|pl|py|jsp|asp|htm|shtml|sh|cgi)$') {
    return 403; 
}
Run Code Online (Sandbox Code Playgroud)

相同的服务器块

解决方案2

上传访问:

if ($http_referer !~ '^http://(.+\.)?foo\.com/') { 
    rewrite '.*\.(jpe?g|gif|bmp|png)$' '/upload/nohotlink.gif' break; 
} 

location ~ \.(php|sql|php3|php4|phtml|pl|py|jsp|asp|htm|shtml|sh|cgi)$ {
    deny all;
}
Run Code Online (Sandbox Code Playgroud)

服务器块:

 location ^~ /upload {
     include /etc/nginx/includes/upload.access;
 }
Run Code Online (Sandbox Code Playgroud)

现在,如果您不设置转发 php 文件处理的位置,您当前的配置将不会导致任何结果:请查看 nginx fastcgi 模块。然后,你将需要改变你的重写规则在root.access文件,以便它们不会在当前位置上下文来解析(即创建一个独特的回退位置和变化breaklast告诉nginx的重写后再次运行位置选择过程)。