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 を土台にしてください。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲