OXY NOTES

WordPressの特定のファイルに対してNginxでIPを規制する方法

ログに流れるスパマーとのイタチごっこも疲れた方に

あまりの普及率にスパマーからも大人気のWordPress。

数あるスパム行為の中でも特に問題なのがwp-login.phpxmlrpc.phpに対して繰り返されるブルートフォース攻撃です。Basic認証を導入するのが一般的な対策ですが、予約投稿が機能しなくなったり、二重にログインするというのも煩わしいものです。

手間のかからない対策をということで、当サイトではSwatchで当該ファイルへの連続したアクセスをフィルタリングしています。

興味のある方は「Swatchでログを監視して、攻撃に合わせた対策を自動で実行する方法」をご覧ください。

これはこれで有効に機能しているのですが、念の為にと導入した「狂骨(Crazy Bone)」というプラグインでログイン履歴を見ると、散発的ながらブルートフォース攻撃が行われています。

規制にかからないように、何種類ものIPを組み合わせて、ゆっくりとしたペースで攻撃しています。(速いペースのものは接続拒否している証拠でもあります)
当サイトではパスワードを強固なものにしているので、この程度の総当たり攻撃では1000年続けても破られることはありません。またペースも遅いのでリソースの消費も無視して良い程度です。

まず安心して良い状況と言えますが、ログイン情報に自分以外のIPが列挙されるというのも精神衛生上よくありません。ログを見てみると、どれか特定の国というわけでもなく、様々な国から来ているので国単位での規制も難しいようです。

そこでタイトルにある通りWordPressの特定のファイルを対象に、NginxでIPによる規制をかけることになりました。


NginxでIPによる規制をかける方法

前置きが長くなりましたが、方法は至って簡単です。
まずはNginxのディレクティブについて簡単に解説します。

Nginxのディレクティブについて

Nginxのlocationディレクティブの書式は以下のようになっています。

location プレフィックス URIのパス {
    [locationコンテキスト]
}

プレフィックスの種類と意味

プレフィックス 意味
なし 前方一致
^~ 前方一致。一致したら、正規表現の条件を評価しない。
= 完全一致。パスが等しい場合。
~ 正規表現(大文字・小文字を区別する)
~* 正規表現(大文字・小文字を区別しない)

プレフィックスごとの優先順位は「完全一致 > 前方一致 > 正規表現 > なし」となっており、それぞれ「最長一致 > 部分一致」となってます。

詳しく知りたい方は「こちらのサイト」で詳しく解説されています。

今回は正規表現で部分一致した場合にIPを規制します。

具体的にはWordPressを動かしているserverディレクティブに以下の記述を追加するだけです。

バックエンドサーバ側ではないので注意。

また、正規表現で一致した項目に関する設定はそこで終了するので順序に気をつけてください。serverディレクティブのlocationに関する設定の先頭に追加すれば安心です。

Nginxの設定の優先順位については「Nginx で location の判定方法と優先順位を調べる」で詳しく解説されています。
# admin-ajax.phpを使うプラグインがあるので例外に登録
location ~ wp-login\.php$|xmlrpc\.php$|wp-admin/((?!admin-ajax\.php).)*$ {
    allow 0.0.0.0/16; # 自分の固定IPや、ISPのIPアドレス
    allow 153.122.40.105; # サーバ自体のIP
    allow 127.0.0.1;
    deny all;
    proxy_pass http://backend;
}

正規表現なのでドットはバックスラッシュでエンティティ処理。また「.php」という名前が途中に入ることは考えにくいですが、文末を示す「$(ドルマーク)」を指定しています。

同じようにxmlrpc.phpwp-adminについての処理を「|(パイプ)」で繋げています。

追記:admin-ajax.phpを利用するプラグインがあるので(WordPress Popular Postsなど)例外として許可する設定に変更しました。またWordPress Popular Postsは一度しかカウントしないtokenを発行するので、リバースプロキシやキャッシュ系プラグインが有効な場合は設定画面でAjaxify widgetを有効にする必要があります。

コンテキストには「allow <IPアドレス>」といった書式でホワイトリスト形式でIPを追加します。
ログインするIPが固定なら固定IPアドレス。もしくはISP(インターネットサービスプロバイダー)に割り振られたIPの範囲を指定。サンプルにあるようにサブネットマスクも使えるので指定は簡単です。

ISPに割り振られたIPの範囲を知りたい場合は以前の投稿で紹介した「JPNIC WHOIS Gateway」などを利用してください。

続けてサーバのIPアドレスローカルIPアドレスを追加。

最後の「proxy_pass http://backend」は、別の場所で定義したバックエンドサーバを指定しています。
普通にphp-fpmで実行するだけなら以下のように直接書いても問題ありません。

fastcgi_pass   unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index  index.php;
fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
include        fastcgi_params;

後はnginxを再起動すれば、設定が有効になります。
記載したIP以外でアクセスすると403エラーになります。試しに自分の固定IPアドレスをコメントアウトしてテストしてみてください。