2026年5月20日
2026年5月20日
WordPressのログイン試行回数を制限する方法|プラグイン・自作コード・Nginx/Apache
WordPress 本体には、ログインに失敗した回数を数えて一時的に締め出す仕組みがありません。そのままではパスワードの総当たり(ブルートフォース攻撃)を何度でも試せるため、試行回数の制限を加えておくと安心です。
この記事では、次の4つの方法を説明します。内容は2026年11月時点で確認したものです。
| 方法 | 向いている場面 |
|---|---|
| プラグイン(Limit Login Attempts Reloaded) | 管理画面だけで設定したい。ほとんどのサイトはこれで足りる |
| mu-plugin で自作 | プラグインを増やしたくない。仕組みを理解して小さく入れたい |
Nginx の limit_req |
サーバーの設定を触れる。PHP に届く前に回数を絞りたい |
| Apache でログイン画面を IP 制限 | 管理者の接続元 IP が決まっている |
パスワードが漏れた場合に備える対策としては、二段階認証も合わせて検討してください(WordPressの二段階認証を設定する方法)。
方法1: Limit Login Attempts Reloaded を使う
wordpress.org で配布されている無料プラグインです。配布ページでの表示名は「Limit Login Attempts Security」に変わっていますが、プラグインのスラッグは limit-login-attempts-reloaded のままです(2026年11月時点の最新は 3.4.2)。
インストール
管理画面の「プラグイン」→「新規プラグインを追加」で「Limit Login Attempts」を検索してインストールし、有効化します。WP-CLI が使える場合は次のとおりです。
wp plugin install limit-login-attempts-reloaded --activate
設定画面と初期値
有効化すると、管理画面の左メニューに「Limit Login Attempts」が追加されます(設定で左メニューを表示しない場合は「設定」の下に入ります)。「Settings」タブの「Local App」欄で、次の値を変更できます。初期値はプラグインのソースコードで確認したものです。
| 画面の項目 | 意味 | 初期値 |
|---|---|---|
| allowed retries | ロックアウトまでに許す失敗回数 | 4回 |
| minutes lockout | 1回のロックアウトの長さ | 20分 |
| lockouts increase lockout time to … hours | 指定回数ロックアウトされたら長期ロックアウトに切り替える | 4回で24時間 |
| hours until retries are reset | 失敗回数を数え直すまでの時間 | 24時間 |
同じ画面の「Notify on lockout」で、ロックアウトが起きたときに管理者へメールを送る設定もできます。
自分の IP を締め出さないために
「Logs」タブの「Safelist」に自分の IP アドレスを登録すると、その IP はロックアウトの対象外になります。逆に「Denylist」に入れた IP はログインできなくなります。
サイトの前に Cloudflare などの CDN やリバースプロキシがある場合、PHP から見える接続元(REMOTE_ADDR)がプロキシの IP になり、全員が同じ IP として数えられてしまいます。「Settings」タブの「Trusted IP Origins」で、実際の接続元が入るサーバー変数(たとえば HTTP_CF_CONNECTING_IP や HTTP_X_FORWARDED_FOR)を指定してください。プロキシを使っていないサイトでこれらを指定すると、攻撃者がヘッダーを偽って制限をすり抜けられるため、使っている構成に合わせて設定します。
ロックアウトを解除する
ログインできる管理者がいれば、「Logs」タブの「Active lockouts」に締め出し中の IP が表示され、「Unlock」で解除できます。
自分が締め出された場合は、プラグインの FAQ で次の方法が案内されています。
- スマートフォンの回線や VPN など、別の IP からログインする
- それができなければ、FTP やサーバーのファイルマネージャーで
wp-content/plugins/limit-login-attempts-reloadedのフォルダー名を一時的に変えてプラグインを止め、ログインしてから名前を戻し、自分の IP を Safelist に登録する
WP-CLI が使える単一サイトでは、締め出し中の IP の一覧は limit_login_lockouts というオプションに保存されています(IP アドレスと解除時刻の組)。次のように空にすると、すべてのロックアウトが解除されます。
# 現在のロックアウトを確認
wp option get limit_login_lockouts --format=json
# すべてのロックアウトを解除
wp option update limit_login_lockouts '[]' --format=json
この保存形式はプラグインの内部仕様なので、通常は管理画面から操作してください。
方法2: mu-plugin で自作する
プラグインを入れずに最低限の制限を加える例です。失敗を数えるのは wp_login_failed アクション、締め出しの判定は authenticate フィルターで行います。
authenticate フィルターでは、WordPress 本体のユーザー名・パスワードの確認が優先度 20 で動きます。優先度 30 で判定すると、ロック中は正しいパスワードを入れてもログインできないようにできます。失敗を数える側を authenticate の中で書くと、ロック中に正しいパスワードで入れてしまう抜けができるため、数えるのは wp_login_failed に分けています。
wp-content/mu-plugins/login-limit.php として保存します(mu-plugins フォルダーが無ければ作ります。中のファイルは自動で読み込まれ、管理画面から停止できません)。
<?php
/**
* Plugin Name: Login Limit (simple)
* Description: 同じIPからのログイン失敗が続いたら一定時間ログインを止める。
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
const MY_LOGIN_MAX_FAILURES = 5; // ロックするまでの失敗回数
const MY_LOGIN_LOCK_SECONDS = 1200; // ロックの長さ(秒)
function my_login_limit_key() {
$ip = isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : '';
return 'my_login_fail_' . md5( $ip );
}
// ログインに失敗したら回数を数える。
add_action( 'wp_login_failed', function () {
$key = my_login_limit_key();
$count = (int) get_transient( $key );
set_transient( $key, $count + 1, MY_LOGIN_LOCK_SECONDS );
} );
// 失敗が規定回数に達していたら、パスワードが正しくても通さない。
add_filter( 'authenticate', function ( $user, $username ) {
if ( '' === trim( (string) $username ) ) {
return $user;
}
if ( (int) get_transient( my_login_limit_key() ) >= MY_LOGIN_MAX_FAILURES ) {
return new WP_Error(
'too_many_retries',
'ログインの失敗が続いたため、しばらくログインできません。時間をおいて再度お試しください。'
);
}
return $user;
}, 30, 2 );
動きと注意点です。
- ロック中にログインを試すと、その試行も失敗として数えられ、ロックの残り時間が20分に戻ります。
- 数えた回数はトランジェント(
_transient_my_login_fail_…オプション、またはオブジェクトキャッシュ)に保存されます。解除したいときは、該当の IP の md5 を使ってwp transient delete my_login_fail_<md5>を実行するか、wp transient delete --allでまとめて消します(ほかのトランジェントも消えますが、通常は再生成されます)。 - CDN やリバースプロキシの配下では、
REMOTE_ADDRがプロキシの IP になります。その場合はサーバー側(Nginx のreal_ipモジュールや Apache のmod_remoteip)で本来の接続元に置き換えてから使ってください。転送ヘッダーを PHP でそのまま信用すると、偽装で制限を回避されます。 - XML-RPC(
xmlrpc.php)経由のログインもauthenticateを通るため、この制限の対象になります。XML-RPC を使っていなければ止めておくのも有効です(WordPressのXML-RPCを無効化する方法)。
方法3: Nginx の limit_req で回数を絞る
Nginx を自分で設定できる場合は、wp-login.php への POST(ログインの送信)だけを IP ごとに回数制限できます。PHP まで届かないので、サーバーの負荷も抑えられます。
http ブロック(/etc/nginx/nginx.conf や conf.d/*.conf)に次を書きます。map で GET のときはキーを空にしています。limit_req_zone はキーが空のリクエストを数えないため、ログイン画面の表示は制限されません。
map $request_method $wp_login_limit_key {
POST $binary_remote_addr;
default "";
}
# 1つのIPにつき1分あたり6回まで(平均10秒に1回)
limit_req_zone $wp_login_limit_key zone=wp_login:10m rate=6r/m;
サイトの server ブロックに、wp-login.php 用の location を追加します。PHP を渡す部分は、すでにある location ~ \.php$ の中身と同じものを書いてください(下の include と fastcgi_pass は Debian / Ubuntu の PHP 8.3 の例です)。
location = /wp-login.php {
limit_req zone=wp_login burst=5 nodelay;
limit_req_status 429;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
burst=5 nodelayで、短い間に5回までは待たせずに受け付け、それを超えた分は 429 を返します。location = /wp-login.phpは完全一致なので、location ~ \.php$より優先されます。- 設定後は
sudo nginx -tで文法を確かめてからsudo systemctl reload nginxで反映します。
この方法は回数を絞るだけで、何回失敗したら締め出すといった判定はしません。方法1や方法2と組み合わせて使います。
方法4: Apache でログイン画面を IP で制限する
管理者の接続元 IP が固定されている場合は、回数を数えるより、wp-login.php に決まった IP からしか接続できないようにするほうが、攻撃の多くを入口で止められます。Apache 2.4 では次のように書きます(WordPress を置いたディレクトリーの .htaccess の先頭)。
<Files "wp-login.php">
Require ip 203.0.113.10
Require ip 198.51.100.0/24
</Files>
Require ipを複数書くと、どれかに一致すれば許可されます。それ以外の接続には 403 を返します。- Apache 2.2 の
Order deny,allow/Deny from all/Allow fromは 2.4 では古い書き方です(mod_access_compatが無いと動きません)。 .htaccessでRequireを使うには、サーバー側でAllowOverride AuthConfig(またはAll)が許可されている必要があります。- 会員サイトなど、管理者以外もログインするサイトでは使えません。接続元 IP が変わる回線では、自分も締め出されます。
詳しい書き方はWordPressのログインページにIP制限をかける方法でも説明しています。
設定するときの注意
- 会社や学校など、多くの人が同じ IP からアクセスする環境では、1人の失敗で全員が締め出されることがあります。失敗回数を少なくしすぎないようにします。
- 制限は総当たりを遅らせる対策です。推測されにくいパスワードと二段階認証を合わせて使ってください。
- プラグインと自作コードを両方入れると、回数の数え方が重なって想定より早くロックされます。どちらか1つにします。
まとめ
- 手軽に始めるなら Limit Login Attempts Reloaded を入れ、自分の IP を Safelist に登録し、CDN を使っていれば Trusted IP Origins を設定します。
- プラグインを増やしたくない場合は、
wp_login_failedで数えてauthenticate(優先度30)で止める mu-plugin で同じことができます。 - サーバーを触れる場合は、Nginx の
limit_reqや Apache のRequire ipで、PHP に届く前に絞ると効果が上がります。