本文へスキップ
サーバーと .htaccess

本当に効く WordPress の .htaccess セキュリティ設定

WordPress の .htaccess セキュリティとして売られているものの大半は水増しです。攻撃対象領域を実際に変える設定はごく短い。どれが本物でどれがそうでないかを解説します

公開

「WordPress の .htaccess セキュリティ」として売られているものの大半は水増しです。攻撃対象領域を実際に変える設定はごく短く、wp-content/uploads 内での PHP 実行をブロックする、wp-config.php への直接アクセスを拒否する、ディレクトリの一覧表示を無効化する、この3つだけです。よく見かける「ブルートフォース対策のため」の xmlrpc.php ブロック、WordPress のバージョン隠し、200行もある悪質ボットのユーザーエージェント一覧の貼り付け、こうしたものは効果が薄いものから完全な茶番までさまざまです。以下で、どれが本物でどれがそうでないか、そしてその理由を説明します。

まず最初にはっきりさせておくべきこと。.htaccess が何かをするのは Apache(および .htaccess を読む LiteSpeed)だけです。nginx では完全に無視されます。ファイルはそこに置かれているだけで、あなたは守られていると思い込んでいる状態になります。もしホストが nginx で動いているなら、ここに書かれていることは一切当てはまらず、代わりに server/location ブロックが必要です。サーバーが一度も読まないファイルの編集に1時間を費やす前に、curl -I https://yoursite.com を実行して Server: ヘッダーを確認してください。

本当に重要な設定:/uploads で PHP を実行させない

やる価値があるのはこれです。wp-content/uploads は設計上、誰でも書き込み可能になっています。メディアのアップロードも、ファイルを保存するあらゆるプラグインも、ここに書き込みます。攻撃者が(脆弱なアップロード処理、MIME タイプを検証しない画像フィールド、改ざんされたプラグインなどを通じて).php ファイルをこのディレクトリに送り込めた場合、それが単なる面倒事で済むか、それとも完全なリモートコード実行の侵害に発展するかを分けるのは、リクエストされたときにサーバーがそのファイルを実行するかどうかです。実行を拒否すれば、アップロードされたペイロードはディスク上に置かれた無害なファイルにすぎなくなります。

これを wp-content/uploads/.htaccess に記述してください(ファイルが存在しなければ新規作成します)。

<FilesMatch "\.php$">
    Require all denied
</FilesMatch>

これは Apache 2.4 の書き方です。古い 2.2 では Order Deny,Allow / Deny from all が同等の記述になります。この2つの方言を1つのファイルで混在させることが、「ハードニング」後に突然 500 Internal Server Error が発生する最も多い原因です。保存した瞬間にサイト全体が落ちるなら、ほぼ間違いなくこれが原因です。バージョンは apachectl -v で確認できます。

wp-config.php を保護する

wp-config.php にはデータベースの認証情報と認証用ユニークキーが格納されています。PHP が動いている間は、このファイルへの直接リクエストは空白のページを返します。PHP がファイルを出力するのではなく実行するからです。リスクは失敗したときのケースです。PHP がクラッシュしたり、移行中に設定が壊れたり、ハンドラーが無効になったりすると、Apache はこのファイルをプレーンテキストとして配信し、リクエストした相手全員に DB のパスワードをさらけ出します。アクセスを拒否しておくのは、まずい5分間に備える安価な保険です。

<Files wp-config.php>
    Require all denied
</Files>

ディレクトリの一覧表示をオフにする

index.php のないフォルダを誰かが訪れたとき、Apache で Options +Indexes が有効になっていると、その中身が一覧表示されます。あらゆるバックアップファイル、忘れていた SQL ダンプまで見えてしまいます。サイト全体でオフにしましょう。

Options -Indexes

深刻度は低いですが、実在するリスクで、しかもコストはゼロです。

これが正直なところの核心となる一覧です。フォーラムの投稿(間違った Apache バージョン向けに書かれたもの)からコピペするのではなく、WordPress .htaccess の書き方ツールを使えば、これらの設定を、サイトを 500 にしないための正しい 2.4 対 2.2 の構文込みで組み立てられます。

やってはいけないこと

「ブルートフォース対策のため」の xmlrpc.php ブロック。 これは誰もが繰り返す代表例ですが、そう言い切るのは間違いです。確かに XML-RPC の system.multicall メソッドは、かつて攻撃者が多数のログイン試行を1つのリクエストにまとめることを可能にしていました。実際の増幅攻撃です。しかし圧倒的に多いブルートフォースの経路は wp-login.php への単純な POST リクエストであり、xmlrpc.php をブロックしてもそれには何の効果もありません。ブルートフォースを防ぐのはレート制限、強力なパスワード、2要素認証であって、1つのエンドポイントを潰すことではありません。XML-RPC を無効化する正当な理由はあります。ピンバック機能が DDoS のリフレクション攻撃に悪用されうるため、Jetpack もモバイルアプリもピンバックも使っていないなら、これを閉じることで攻撃対象領域は狭まります。ただしそれがブルートフォース対策だと自分に言い聞かせるのはやめましょう。そうではないからです。

WordPress のバージョン隠し/ジェネレータータグの削除。 readme.html<meta name="generator"> タグを取り除くとハードニングした気になります。しかし攻撃者は、読み込まれるアセットのクエリ文字列、ブロックエディターのマークアップ、その他いくつもの手がかりから、数秒であなたのバージョンを特定します。何も隠せておらず、忙しく作業した気分になっているだけです。

巨大な悪質ボットのユーザーエージェントとリファラーのブロックリスト。 ユーザーエージェントは偽装可能な HTTP ヘッダー1つにすぎません。この手のリストは貼り付けたその日にはもう古く、まともな攻撃者は何も止められず、そのうえ Apache はすべてのリクエストですべての正規表現を評価します。セキュリティ効果ゼロのために、実際のパフォーマンスの代償を払っているのです。やめましょう。

wp-login.php の IP 制限。 ISP がアドレスをローテーションして自分の管理画面から締め出されるまでは素晴らしい方法です。本当に固定 IP がある場合にのみ現実的です。

投稿者列挙のリダイレクト(?author=1)。 これ用に貼り付けられる .htaccess の書き換えルールは、それ単体では不完全です。REST エンドポイントの /wp-json/wp/v2/users は依然としてユーザー名を一覧表示します。一方のパスをブロックしてもう一方を開けたままにするのは茶番です。

それでも解決しない場合

ある設定でサイトが 500 になったら、それは構文の問題です。最後に追加したブロックを外して再読み込みすれば、すぐに切り分けられます。ある設定が何も効いていないように見えるなら、本当に Apache 上で動いているか、そしてそのディレクトリで AllowOverride が有効になっているか(多くのマネージドホストはこれを制限しています)を確認してください。.htaccess の書き方ツールで、動作確認済みのテンプレートからファイルを組み立て、重要な3つの設定を残して、あとは捨てましょう。