2026年5月20日
2026年5月20日
WordPressのブルートフォース攻撃対策:ログイン試行制限・IP制限・2FA・Fail2ban
ブルートフォース攻撃(総当たり攻撃)は、ユーザー名とパスワードの組み合わせを自動で大量に試す攻撃です。WordPress 本体にはログインの失敗回数を制限する機能がないため、何も対策しないと試行を受け続けます。
対策は1つに頼らず、次のように層を重ねるのが基本です。
| 層 | 対策 | 主な効果 |
|---|---|---|
| アカウント | 推測されにくいパスワード、二要素認証 | パスワードが当たってもログインさせない |
| WordPress | ログイン試行回数の制限、XML-RPC の停止 | 同じ IP からの連続した試行を止める |
| Web サーバー | wp-login.php の IP 制限・Basic 認証・レート制限 | PHP に届く前に止め、負荷も下げる |
| OS | Fail2ban | 失敗を繰り返す IP をファイアウォールで遮断 |
攻撃を受けているか確認する
アクセスログで wp-login.php と xmlrpc.php への POST を数えます。パスは Ubuntu の Apache の例で、Nginx なら /var/log/nginx/access.log です。
# wp-login.php に POST している IP の上位
grep '"POST /wp-login.php' /var/log/apache2/access.log \
| awk '{print $1}' | sort | uniq -c | sort -rn | head -20
# xmlrpc.php への POST も確認
grep -c '"POST /xmlrpc.php' /var/log/apache2/access.log
ログインに失敗すると WordPress はログイン画面をもう一度表示するため、ステータスは 200 になります。成功するとリダイレクトするため 302 です。同じ IP から 200 の POST が大量に並んでいれば、総当たりを受けています。
ログイン試行回数を制限する
プラグインで制限する
管理画面だけで設定したい場合は、ログイン試行制限のプラグインを使います。例として Limit Login Attempts Reloaded(2026年11月時点で有効インストール数 100万以上)があります。
wp plugin install limit-login-attempts-reloaded --activate
管理画面からインストールする場合は「プラグイン」→「新規追加」で名前を検索します。Wordfence などのセキュリティプラグインにも同様の機能があるので、すでに使っているならそちらの設定を確認します。同じ機能を持つプラグインを重ねて入れる必要はありません。
コードで制限する
プラグインを増やしたくない場合は、次のコードを wp-content/mu-plugins/login-limit.php として置きます(mu-plugins ディレクトリが無ければ作ります)。同じ IP からの失敗が 5 回に達すると、15 分間ログインを受け付けません。
<?php
/**
* Plugin Name: Simple Login Limit
* Description: 同じ IP からのログイン失敗が続いたら一定時間ログインを止める。
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
const SLL_MAX_FAILS = 5;
const SLL_LOCK_MINUTES = 15;
function sll_key(): string {
$ip = isset( $_SERVER['REMOTE_ADDR'] ) ? (string) $_SERVER['REMOTE_ADDR'] : '';
return 'sll_fail_' . md5( $ip );
}
// 認証の最後(本体のパスワード確認は優先度 20)で、上限を超えていれば拒否する
add_filter(
'authenticate',
function ( $user, $username ) {
if ( '' === (string) $username ) {
return $user;
}
if ( (int) get_transient( sll_key() ) >= SLL_MAX_FAILS ) {
return new WP_Error(
'sll_locked',
sprintf( 'ログインの失敗が続いたため、%d 分間ログインできません。', SLL_LOCK_MINUTES )
);
}
return $user;
},
30,
2
);
// 失敗したら回数を増やす
add_action(
'wp_login_failed',
function () {
$fails = (int) get_transient( sll_key() );
set_transient( sll_key(), $fails + 1, SLL_LOCK_MINUTES * MINUTE_IN_SECONDS );
}
);
// 成功したら回数を消す
add_action(
'wp_login',
function () {
delete_transient( sll_key() );
}
);
- 回数はトランジェントに保存します。永続オブジェクトキャッシュ(Redis など)を使っている場合はそちらに入るため、キャッシュを全消去すると回数もリセットされます。
- Cloudflare やロードバランサーの後ろにあると、
REMOTE_ADDRがプロキシの IP になり、全員がまとめて止められます。その場合は PHP でHTTP_CF_CONNECTING_IPなどのヘッダーを直接信用せず(偽装できるため)、Apache のmod_remoteipや Nginx のreal_ipモジュールで、信頼するプロキシからの接続に限って本来の IP に置き換える設定をします。
コードでの制限は プラグインなしでログイン試行回数を制限する方法 でも詳しく扱っています。
wp-login.php へのアクセスを Web サーバーで制限する
PHP まで届く前に止めると、サーバーの負荷も下がります。設定を変える前に、SSH や管理会社のコントロールパネルなど、Web 以外の方法で設定を戻せることを確認してください。
Apache 2.4:IP アドレスで制限する
固定 IP からしか管理しない場合は、.htaccess(または VirtualHost の設定)に書きます。
<Files "wp-login.php">
Require ip 203.0.113.10
Require ip 198.51.100.0/24
</Files>
.htaccess で Require を使うには、そのディレクトリの AllowOverride に AuthConfig(または All)が必要です。Order Deny,Allow / Allow from は Apache 2.2 の書き方です。Apache 2.4 では mod_access_compat が無効だとエラーになるため、Require ip を使います。
Apache 2.4:Basic 認証をかける
IP が固定でない場合は、wp-login.php に Basic 認証を追加します。WordPress のパスワードの前にもう1つ関門ができます。
sudo apt install apache2-utils
sudo htpasswd -c /etc/apache2/.htpasswd-wplogin loginadmin
<Files "wp-login.php">
AuthType Basic
AuthName "Restricted"
AuthUserFile /etc/apache2/.htpasswd-wplogin
Require valid-user
</Files>
-c はファイルを新規作成するオプションです。2人目以降を追加するときは -c を付けずに実行します(付けると上書きされます)。パスワードリセットの画面も wp-login.php なので、会員サイトなど一般の利用者がログインするサイトでは、この方法は向きません。
Nginx:レート制限と IP 制限
Nginx では limit_req で、同じ IP からのリクエストの速さを制限できます。limit_req_zone は http ブロックに書きます。
# /etc/nginx/nginx.conf の http { } の中
limit_req_zone $binary_remote_addr zone=wplogin:10m rate=6r/m;
# サイトの server { } の中
location = /wp-login.php {
limit_req zone=wplogin burst=5 nodelay;
limit_req_status 429;
# 固定 IP だけに絞る場合
# allow 203.0.113.10;
# deny all;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
rate=6r/mは 1 分あたり 6 回(10 秒に 1 回)で、burst=5までは超過を許します。snippets/fastcgi-php.confは Ubuntu の nginx パッケージに含まれる設定です。ソケットのパスは PHP の版で変わるので、ls /run/php/で確認して合わせます。- 設定後は
sudo nginx -tで文法を確認してからsudo systemctl reload nginxで反映します。
XML-RPC を止める
xmlrpc.php は、ログイン画面を通らずにユーザー名とパスワードを送れる入口です。スマートフォンアプリや Jetpack など XML-RPC を使う機能が無ければ止めます。
認証が必要な XML-RPC のメソッドだけを止めるなら、WordPress 本体のフィルター xmlrpc_enabled を使います(ピンバックなど認証が要らない機能は残ります)。
<?php
// wp-content/mu-plugins/disable-xmlrpc-auth.php
add_filter( 'xmlrpc_enabled', '__return_false' );
ファイルごと止めるなら Web サーバーで拒否します(Apache 2.4 の例)。
<Files "xmlrpc.php">
Require all denied
</Files>
二要素認証を入れる
パスワードが当たってしまっても、二要素認証(2FA)があればログインはできません。WordPress の公式機能プラグイン Two Factor や、ロール単位で利用を強制できる WP 2FA などがあります。
wp plugin install two-factor --activate
管理者や編集者に 2FA を設定させる方法は WordPressで二要素認証(2FA)を強制する方法 で説明しています。
Fail2ban で失敗を繰り返す IP を遮断する
Fail2ban はログを監視し、条件に合った IP をファイアウォールで一定時間遮断します。WordPress 用のフィルターは標準では含まれていないので作ります。
sudo apt install fail2ban
フィルター /etc/fail2ban/filter.d/wordpress-login.conf を作成します。wp-login.php への POST のうち、失敗を示すステータス 200 だけを数えます。
[Definition]
failregex = ^<HOST> \S+ \S+ \[[^\]]*\] "POST /wp-login\.php[^"]*" 200\s
ignoreregex =
Apache・Nginx の標準のログ形式(combined)を想定しています。ログに当てはまるかは fail2ban-regex で確認できます。
sudo fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/wordpress-login.conf
結果の Lines: ... matched に件数が出れば一致しています。次に jail を /etc/fail2ban/jail.d/wordpress-login.local に作ります。
[wordpress-login]
enabled = true
port = http,https
filter = wordpress-login
logpath = /var/log/apache2/access.log
backend = auto
maxretry = 5
findtime = 10m
bantime = 1h
backend = auto は、ディストリビューションの既定設定が journal(systemd)を読む設定になっていても、logpath のファイルを監視させるために書いています。
sudo systemctl restart fail2ban
sudo fail2ban-client status wordpress-login
遮断した IP の一覧が Banned IP list に表示されます。自分の IP を誤って遮断した場合は sudo fail2ban-client set wordpress-login unbanip 203.0.113.10 で解除します。
注意点
- IP 制限や Basic 認証、2FA の強制は、設定を誤ると自分も締め出されます。SSH でファイルを戻せる状態にしてから変更してください。
- Cloudflare などのプロキシを通している場合、Web サーバーのログと Fail2ban が見る IP はプロキシのものになります。前述の
mod_remoteipなどで本来の IP をログに記録する設定が先に必要です。また、Fail2ban がサーバーのファイアウォールで遮断しても、プロキシ経由の通信は止まりません。 - 攻撃元の IP は次々に変わることが多く、IP の遮断だけでは防ぎきれません。推測されにくいパスワードと 2FA を土台にしてください。