web-dev-qa-db-ja.com

Nginx書き換えルール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]

2番目の.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>

そして、3番目で最後の.htaccessファイルは、「small」という名前のアップロードフォルダのサブディレクトリにあります。

RewriteEngine Off

これで、/ 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; 
}

「upload」フォルダーにある2番目のファイルについて、upload.accessというファイルを/ etc/nginx/includesに作成しました。このファイルには次のものが含まれています。

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

そして、3番目の最後のファイルについては、/ etc/nginx/includesの名前small.accessにファイルを作成しました。このファイルの内容は次のとおりです。

# nginx configuration 

location /upload/small { 
}

サーバーブロック構成ファイルには、次のものがあります。

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

この構成では、サイトを試すときに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エラーを超える書き換えルールがまったく正しく機能しないことも心配です。誰かがこれで私を助けることができますか?ここで何が悪いのかわかりません。

3
Adrian

これは、構成のこの部分の標準的な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が構成ファイルを読み取ると、ロケーションブロックが3つのタイプに分類されます:

  • 正確なロケーションブロック(例: location = /upload { }
  • プレフィックス付きロケーションブロック(例: location /upload { }
  • 正規表現を含むロケーションブロック例: location ~ /upload { }

リクエストがnginxに届くと、場所の選択プロセスは次のようになります。

  1. URIに一致する正確なロケーションブロックが見つかった場合、nginxは他のロケーションブロックの検索を停止し、このリクエストを処理します。
  2. そうでない場合、nginxは最も長く一致するプレフィックス付きロケーションブロックを検索し、次のステップに進む前にそれを記憶します。
  3. 次に、nginxは正規表現を含むロケーションブロックを順番にチェックします。最初に一致したものがリクエストの処理に使用されます。
  4. 前のステップで何も見つからなかった場合、nginxはステップ2のプレフィックス付きロケーションブロックを使用してリクエストを処理します。何も見つからなかった場合、いくつかのことが起こる可能性がありますが、それはトピックから外れています。

したがって、あなたの場合、.php拡張子に一致するロケーションブロックは、URIの/upload部分に一致するロケーションブロックよりも優先されます。

編集:ソリューションの明確化、代替ソリューションが追加されました。

^~を使用すると、nginxにステップ2の動作を変更するように指示できます。これにより、正規表現の場所の検索をバイパスして、一致するプレフィックス付きの場所がすぐに使用されます。したがって、2つの解決策があります:

ソリューション1

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

同じサーバーブロック

ソリューション2

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ファイル処理を転送する場所を設定しない場合、現在の構成では何も起こりません。nginx fastcgi module を確認してください。次に、root.accessファイルの書き換えルールを変更して、現在の場所のコンテキストで解決されないようにする必要があります(つまり、一意のフォールバック場所を1つ作成し、breaklastに変更してnginxに通知します。書き換え後に場所選択プロセスを再度実行します)。

9
Xavier Lucas