マルチサイト化したWordPressで、wp-content下の存在しないファイルにアクセスされるとリダイレクトループに陥るのを直す。

WordPressを設置したサーバのアクセスログを見ていたら、おそらく悪意を持った訪問者が /wp-content/plugins/ ディレクトリの中の存在しないファイルに頻繁にアクセスしていて、"404 Not Found" ではなく "500 Internal Server Error" が記録されている。

Apacheのエラーログも見てみると、

Request exceeded the limit of 10 internal redirects due to probable configuration error.

…どうやらリダイレクトループに陥っているらしい。たぶん .htaccess の設定が原因だろう。

うちは「ルートディレクトリにWordPressをインストール。サブディレクトリに子サイトを設置」というマルチサイト環境なのですが、その場合に WordPress 6.2が用意してくれる .htaccess の中身は以下のようなもの。

最後のブロックの書き換えルールが怪しそう。さて、どう直せばよいのやら。

いろいろ試行錯誤してみたけれど、WordPressの正常動作とリダイレクトエラーの解消とを両立させる方法がなかなか見つからない。

数日のあいだ頭を抱えていたところ、遂に、ズバリの解決策を提示してくれているページを発見。

どういう理屈かは元記事読んでいただくとして、どうすれば良いかだけ書くと…

解決策 その1

後ろから3行目と2行目の ? を削除。すなわち…

RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]

を、

RewriteRule ^([_0-9a-zA-Z-]+/)(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)(.*\.php)$ $2 [L]

に修正する。あるいは、

解決策 その2

後ろから3行目の前に条件を追加して、以下のようにする。

RewriteCond %{REQUEST_URI} !^/wp-(content|admin|includes).*$
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]
RewriteRule . index.php [L]

もしくは、

解決策 その3

後ろから6行目〜4行目のルールの前に、ひとつ条件を追加する。

RewriteCond %{ENV:REDIRECT_STATUS} 200 [OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]

…と、上記のいずれかの修正を .htaccess に加えれば、WordPressは正常に動作し、リダイレクトのループも解消され、存在しないファイルへのリクエストには正しく "404" が返る…という待ちに待った状態に!

一応ざっくり解説すると、存在するファイル/ディレクトリに対するリクエストは、

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]

このブロックに引っかかるので、要求されたURLそのものを返して終了。

「存在しないファイル/ディレクトリ」は次の書き換えルール:

RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]

に進むのだけれど、これは「存在しないファイル/フォルダ」のうち「wp-content , wp-include , wp-admin を含むリクエスト」のみが引っかかる。例えば wp-content ディレクトリの下の、存在しない file.txt というファイルへのリクエスト。

https://example,com/subdir/wp-content/file.txt
 ↓
https://example.com/wp-content/file.txt に書き換えられて、1回目のリダイレクトへ。

すると今度は、リダイレクトされたURL:https://example.com/wp-content/file.txt について判定が行われるのですが、これも「存在しないファイル/ディレクトリ」のうち「wp-content , wp-include , wp-admin を含むリクエスト」という条件に引っかかる。書き換えルール:

RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]

が再び発動。

https://example,com/wp-content/file.txt
 ↓
https://example.com/wp-content/file.txt (URLは書き換えられない!)で、2回目のリダイレクトへ。

以下、同じことが続く…で、無限リダイレクトループが発生してしまう、というわけですね。

なので、上記条件に引っかかるリクエストのリダイレクトを1回だけに抑えてやろう、というのが今回の解決策1〜3です。

「存在しないファイル/ディレクトリ」のうち「wp-content , wp-include , wp-admin を含まない」ものは、このルールをスルーするのでリダイレクトは発生せず、正しく "404 Not Found" が返ります。

素晴らしい。

カテゴリ: