ほかの対策を通り抜けられたときのための設定
管理しているサイトで、セキュリティの設定を見直していたときのことです。外から入られないための対策とは別に、もしそれを通り抜けられたときに被害を広げないための設定も、そろえて入れておくことにしました。入れたのは次の 3 つです。
| 設定 | 止めること |
|---|---|
| uploads のフォルダで PHP を動かさない | プラグインの弱いところを使って uploads に PHP のファイルを置かれても、そのファイルを開いて動かすことができない |
| 管理画面のファイルエディターを止める | 管理者のアカウントを乗っ取られても、管理画面からテーマやプラグインの PHP を書き換えられない |
| readme.html と license.txt を見せない | WordPress のバージョンなど、サイトの中の情報を外に出さない |
どれも、ほかの対策がうまく働いていればふだんは何も起きない設定です。そのぶん、入れても見た目や使い勝手はほとんど変わらないので、まとめて入れておきやすい設定でもあります。
1. uploads のフォルダで PHP を動かさない
uploads は、画像などを管理画面から上げるためのフォルダなので、WordPress がファイルを書き込めるようになっています。そのため、プラグインの弱いところを使われたときに、PHP のファイルが置かれる場所になりやすいフォルダです。画像のフォルダで PHP が動く必要はふつうないので、拡張子が PHP のファイルは開けないようにします。
# BEGIN no-php-in-uploads
<FilesMatch "\.(php|phtml|phar|php[0-9])$">
Require all denied
</FilesMatch>
# END no-php-in-uploads
| 書き方 | 役目 |
|---|---|
<FilesMatch "\.(php|phtml|phar|php[0-9])$"> |
名前の最後が .php・.phtml・.phar・.php7 のようなファイルだけを対象にする。画像や PDF は対象にならない |
Require all denied |
だれが開いても 403 にする。ファイルは開かれないので、中の PHP も動かない |
# BEGIN〜# END |
自分で足した設定だと分かるように区切る |
uploads の .htaccess には、画像を WebP に変えるプラグインなどが自分の設定を書いていることがあります。プラグインは # BEGIN(プラグインの名前) から # END(プラグインの名前) までを設定のたびに書き直すので、その中に書くと消えてしまいます。そのため、プラグインの区切りの外、ファイルの最後に自分の区切りで足しました。また、WebP の変換先のフォルダ(wp-content/uploads-webpc など)があるサイトでは、そのフォルダの .htaccess にも同じ設定を足しています。
入れる前に確かめたこと
この設定を入れると、uploads の中の PHP はどれも開けなくなります。そのため、先に uploads の中に PHP のファイルがあるかを探し、プラグインが uploads の PHP を使っていないかを確かめました。
find wp-content/uploads -name "*.php*"
今回検証したサイトでは、見つかったのはフォルダの中身を一覧で見せないための空の index.php だけでした。この index.php は、開かれたときに何も出さないためのファイルなので、403 になっても困ることはありません。uploads に置いた PHP を画面から呼ぶプラグインがあるときは、この設定で動かなくなるので、入れる前にそのプラグインの説明を確かめておきます。
2. 管理画面のファイルエディターを止める
WordPress には、管理画面からテーマやプラグインのファイルを直せる「テーマファイルエディター」と「プラグインファイルエディター」があります。便利な一方で、管理者のアカウントでログインされてしまうと、そこからテーマの PHP に好きなコードを書き込めてしまいます。wp-config.php に 1 行足すと、このエディターを止められます。
define( 'DISALLOW_FILE_EDIT', true );
| 書き方 | 役目 |
|---|---|
DISALLOW_FILE_EDIT |
管理画面のファイルエディターを止める WordPress の定数 |
true |
止める。外観のメニューの「テーマファイルエディター」と、プラグインのメニューの「プラグインファイルエディター」が出なくなる |
この定数は、wp-settings.php を読み込む行より上に書きます。下に書くと、WordPress が設定を読み終えたあとになるので効きません。止まるのはファイルを直す画面だけなので、記事の編集やプラグイン・テーマの更新は今までどおりできます。ファイルを直すときは、git や SSH、FTP で直す形にしました。
3. readme.html と license.txt を見せない
WordPress のフォルダの直下には、readme.html と license.txt があります。WordPress を更新するたびに置き直されるファイルで、だれでも開ける状態だと、WordPress を使っていることやバージョンの手がかりになります。サイトの表示には使わないファイルなので、サイトの直下の .htaccess で開けないようにしました。
<Files readme.html>
Require all denied
</Files>
<Files license.txt>
Require all denied
</Files>
| 書き方 | 役目 |
|---|---|
<Files readme.html> |
この名前のファイルだけを対象にする |
Require all denied |
開いたときに 403 にする |
ファイルを消すことも考えたのですが、WordPress を更新するとまた置かれるので、.htaccess で止めるほうにしました。セキュリティのプラグインやサーバーの設定で、すでに同じ設定が入っていることもあるので、足す前に .htaccess の中を見ておきます。
確かめた結果
まず作業環境で試し、そのあと本番に入れました。uploads の確かめでは、検証用スクリプト(画面に文字を 1 つ出すだけの PHP)を uploads に置いて開き、確かめたあとはすぐに消しています。
curl -s -o /dev/null -w '%{http_code}\n' "https://example.com/readme.html"
| 確かめたこと | 作業環境 | 本番 |
|---|---|---|
| uploads に置いた検証用スクリプト | 403(動かない) | 試していません(本番には置いていない) |
| uploads の画像 | 200 | 200 |
| トップページ | 200 | 200 |
| readme.html | 403 | 403 |
| license.txt | 403 | 試していません |
本番では、設定を入れたサイトのどれも、トップページとアップロードした画像が今までどおり 200 で開け、readme.html が 403 になりました。
画像のリンク対策(Referer を見て、ほかのサイトからの読み込みを止める設定)が入っているサイトでは、curl で画像を開くと Referer がないので 403 になります。今回の設定で止まったのか、リンク対策で止まったのかが分からなくなるので、画像を確かめるときは -e でサイトの URL を Referer として付けて開きました。
curl -s -o /dev/null -w '%{http_code}\n' -e "https://example.com/" "https://example.com/wp-content/uploads/2025/01/sample.png"
気をつけること
.htaccess や wp-config.php を直す前には、元のファイルのバックアップを作ります。このとき、バックアップを公開のフォルダ(サイトの直下など)に置かないように気をつけてください。たとえば wp-config.php.bak のような名前で置くと、拡張子が .php ではないので PHP として動かず、中身がそのまま文字として読めてしまいます。DB のパスワードなどが入ったファイルなので、バックアップは公開のフォルダの外に作りました。
- uploads の .htaccess は、プラグインの
# BEGIN〜# ENDの区切りの外に書く - 入れる前に、uploads に PHP のファイルがないか、それを使うプラグインがないかを確かめる
DISALLOW_FILE_EDITは wp-settings.php を読み込む行より上に書く- バックアップは公開のフォルダの外に作る
- 画像のリンク対策があるサイトでは、curl に Referer を付けて確かめる
まとめ
- uploads で PHP を動かさない設定は、PHP のファイルを置かれても動かせないようにする
- ファイルエディターを止めると、管理者のアカウントを乗っ取られても管理画面から PHP を書き換えられない
- readme.html と license.txt を 403 にして、WordPress のバージョンなどの手がかりを出さない
- どれも見た目や使い勝手はほとんど変わらないので、そろえて入れておきやすい
