tech

wp-config-sample.phpが500を返していた理由とNginxのlocationを正規表現に変えた話

wp-config-sample.phpが500を返していた理由とNginxのlocationを正規表現に変えた話

毎朝届く LogWatch のレポートを開いたとき、ひとつだけ気になる行がありました。

LogWatch とは、サーバーのログを毎日自動で集計してメール送信してくれる監視ツールです。 何かおかしなアクセスがあったとき、翌朝のレポートで気づけるようにしています。

その日の 5xx エラーは1件だけで、対象のパスは /wp-config-sample.php でした。

.env.git/config へのスキャンは日常的に飛んでくるのですが、それらはすべて 404 で終わっていました。 /xmlrpc.php はすでに 444 でブロック済みです。 ところがこの1件だけが 500 を返していました。

「なぜ 404 じゃなくて 500 なんだろう」──その疑問から調べ始めました。

なぜ 500 になるのか

wp-config-sample.php は、 WordPress に同梱されているサンプルの設定ファイルです。 実際の設定ファイルである wp-config.php の雛形として使われるもので、データベースのパスワードや認証キーなどの機密情報は含まれていません。

問題は、このファイルがサーバー上に実際に存在していたことにあります。

外部スキャナーがアクセスしたとき、 Nginx はファイルを発見して PHP に処理を渡しました。 PHP はファイルを実行しようとしましたが、データベース接続に失敗して内部エラーになりました。 その結果が 500(Internal Server Error)です。

404(ファイルが存在しない)ではなく 500 を返すということは、「ファイルが存在していて、 PHP が動く環境であること」を攻撃者に伝えてしまいます。 404 よりも多くの情報を漏らしてしまう点で、セキュリティ上は好ましくありません。

既存の設定を確認したら穴があった

wp-config.php へのアクセスは、以前から Nginx でブロックしていました。

nginx
location = /wp-config.php { return 444; }

=完全一致を意味します。この書き方では、/wp-config.php というパスにのみマッチします。

見た瞬間に気づきました。-sample.php は完全一致の対象外です。

| URL | 変更前の動作 | |-----|------------| | /wp-config.php | 444 ブロック ✅ | | /wp-config-sample.php | 素通り ❌ | | /wp-config.php.bak | 素通り ❌ | | /WP-CONFIG.PHP(大文字) | 素通り ❌ |

「ブロックしていたつもり」が、バリエーションに対応できていませんでした。

return 444 か return 403 か

ブロック方法を変える前に、レスポンスコードをどうするかを考えました。

return 403(Forbidden)は、アクセスを拒否したことを相手に伝えます。 アクセスログに残るため、監視しやすいという利点があります。

return 444 は Nginx 独自の設定で、応答を返さずに接続を切断します。 相手から見ると「応答がない」だけで、ブロックされているのか存在しないのかも判断できません。

今回は 444 を選びました。 攻撃者にできるだけ情報を与えないという判断です。 /xmlrpc.php も同じ理由で 444 にしています。

403 にすることでアクセスログで確認できるようにするという方法も考えましたが、攻撃者にはできるだけ情報を与えないということで、444 にしています。

正規表現マッチに変えた

=(完全一致)から ~*(正規表現・大文字小文字無視)に変更しました。

nginx
location ~* wp-config.*\.php$ { return 444; }

~* は正規表現を使ったマッチングを意味します。 wp-config で始まり .php で終わるすべてのパスにマッチするようになります。

| URL | 変更後の動作 | |-----|------------| | /wp-config.php | 444 ブロック ✅ | | /wp-config-sample.php | 444 ブロック ✅ | | /wp-config.php.bak | 444 ブロック ✅ | | /WP-CONFIG.PHP(大文字) | 444 ブロック ✅ |

変更後に curl コマンドで動作を確認しました。

bash
curl -I https://note.example.com/wp-config-sample.php
curl: (52) Empty reply from server

応答なしで接続が切断されています。正常にブロックされていることを確認できました。

この設定が必要なファイルかの判断

Nginx の設定ファイルが複数ある環境では、どのファイルに変更を加えるかの判断も必要です。

今回の変更対象は WordPress が動いているサイトの設定ファイルだけです。 Next.js のサイトには PHP が存在しないため、wp-config 系のファイルが置かれることはなく、この設定を追加する必要はありません。

設定変更後は、以下のコマンドで構文チェックとリロードを行います。

bash
sudo nginx -t && sudo systemctl reload nginx

nginx -t で構文エラーがないことを確認してからリロードするのが安全です。


LogWatch のレポートは毎日届きますが、ほとんどの日は流し読みで終わります。 それでも「1件だけ 500 がある」という小さな違和感を見逃さなかったことで、設定の穴に気づくことができました。

完全一致で書いたつもりのブロック設定が、バリエーションに対応できていませんでした。 「動いている」と「完全にカバーできている」は別の話だと、改めて感じました。

この記事が役に立ったら、シェアしていただけると嬉しいです!

関連記事