Nginx rewite规则403错误

我在将.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] 

第二个.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> 

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

 RewriteEngine Off 

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

对于位于文档根目录中的第一个.htaccess文件,我在/ etc / nginx / includes中创build了一个名为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; } 

对于位于“upload”文件夹中的第二个文件,我在/ etc / nginx / includes中创build了一个名为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; } 

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

 # nginx configuration location /upload/small { } 

在服务器块configuration文件中我有:

  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; } 

现在使用此configuration时,尝试站点我收到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/" 

现在在Apache下,一切都没有问题。 但我不明白为什么我得到403错误。 我也担心,我所说的改写规则超出了403错误,根本无法正常运作。 谁能帮我这个? 我看不出这里有什么问题。

这是这部分configuration的标准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; } } 

为什么?

让我来澄清位置如何工作:当nginx读取configuration文件时,它将按3种types对位置块进行sorting:

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

一旦请求到达nginx,位置select过程如下:

  1. 如果find与URI匹配的确切位置块,nginx将停止search其他位置块并提供此请求。
  2. 否则,nginx会search最长匹配的前缀位置块,并在进入下一步之前记住它。
  3. 然后nginx依次检查包含正则expression式的位置块。 第一个匹配的将用于服务请求。
  4. 如果在上一步中没有发现任何东西,那么nginx将使用步骤2的前缀位置块来提供请求。 如果没有发现,可能会发生几件事情,但它是无关紧要的。

所以在你的情况下,匹配.php扩展名的位置块优先于匹配URI的/upload部分的位置块。

编辑 :澄清解决scheme,添加替代解决scheme。

使用^~你可以告诉nginx改变他的行为,所以它会立即使用匹配的前缀位置,绕过正则expression式位置查找。 所以你有2个解决scheme:

解决scheme1

upload.access:

 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; } 

相同的服务器块

解决scheme2

upload.access:

 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; } 

服务器块:

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

现在,如果您不设置位置来转发php文件处理,您当前的configuration将不会导致任何事情:检查nginx fastcgi模块 。 然后你将需要在root.access文件中改变你的重写规则,这样它们在当前位置上下文中就不会被parsing(例如,创build一个唯一的备用位置,并改变last的位置以告诉nginx在重写之后再次运行位置select过程) 。