WordPressでセキュリティアップ系のプラグインでログインセキュリティアップを目的として搭載されていることの多い機能の1つ、ログイン試行回数制限を、プラグインなしで実装するコード例を紹介します。
本ページで行う機能要件は以下の通りです。
- 同一のIPアドレスから、同じユーザー名に対して〇回ログインに失敗したらロックアウト(ログイン画面表示の拒否)する
- ロックアウトされたIPアドレスからは△分間ログイン画面の代わりに警告画面を表示する
結構簡単なコードで実装できたので、この機能が欲しいために多用途なセキュリティプラグインを入れている方の代替策になれば幸いです。
本ページ掲載のコードを使用するときは
本ページで掲載しているコードは、以下に了承した上で使用ください
- コードは商用・非商用問わず自由に使っていただいて構いませんが、コード追加による不具合やトラブルが発生しても当方では一切責任を負いません
- コードは有効化しているテーマのfunctions.php、style.cssなどへ追加することで機能します。それらのファイルへの変更を行うことに不安のある方は使用しないでください
- コードは本ページの公開日時点で私の環境において動作したものです。WordPressバージョン他環境の違いによって動作しないことがあります
- コードは、セキュリティ、コードの正確さなどにおいて完全なものではありません。中には紹介するコードを簡略化するために省略している部分があるものもありますので、ご自身でコードを十分に検証し、必要な部分の編集を行った上で使用するようにしてください
- 掲載しているのは参考コードです。自身の環境に合わせるための編集はご自身で対応いただく必要があります(コメント欄等から質問いただいても基本回答は致しません)
- 掲載しているコードの転載を禁じます(SNSで紹介いただいたり、本ページへのリンクを張っていただくことは大歓迎です)
ログイン試行回数制限を設定するコード
以下のコードを有効化しているテーマのfunctions.phpへ追加すると機能します。
/***** ログイン試行回数制限 *****/
/* ログイン失敗時に一定時間メッセージを出す */
function pwcn_limit_login_attempts() {
// 最大試行回数
$max_attempts = 3; //初期値は3回失敗まで
// ロックアウト時間(ここでは5分)
$lock_sec = 5;//分数を指定
$lockout_time = $lock_sec * MINUTE_IN_SECONDS;
// 現在のユーザーIPアドレスとユーザー名を取得
$ip_address = $_SERVER['REMOTE_ADDR'];
if (isset($_POST['log'])) {
$username = sanitize_user($_POST['log']);
} else {
return;
}
$failed_login_key = 'pwcn_failed_login_' . $ip_address . '_' . $username;
$failed_login_count = get_option($failed_login_key, 0);
$first_attempt_time = get_option($failed_login_key . '_time', 0);
//ロックアウト中のメッセージ
$message = 'ログイン試行回数を超えました';
// ロックアウト中か確認
if ($failed_login_count >= $max_attempts) {
if (time() - $first_attempt_time < $lockout_time) {
wp_die( esc_html($message) );
} else {
// ロックアウト時間が経過した場合、カウンターをリセット
delete_option($failed_login_key);
delete_option($failed_login_key . '_time');
}
}
// ログイン試行が失敗した場合
if (isset($_POST['pwd']) && !is_user_logged_in()) {
$failed_login_count++;
update_option($failed_login_key, $failed_login_count);
// 最初の試行時間を記録
if ($failed_login_count === 1) {
update_option($failed_login_key . '_time', time());
}
}
}
add_action('init', 'pwcn_limit_login_attempts');
/* ログイン成功時にオプションを削除 */
/* 無制限にip+ユーザー名でオプションが追加されるのを防ぐ */
function pwcn_reset_failed_login_count() {
// 現在のユーザーIPアドレスとユーザー名を取得
$ip_address = $_SERVER['REMOTE_ADDR'];
if (isset($_POST['log'])) {
$username = sanitize_user($_POST['log']);
} else {
return;
}
$failed_login_key = 'pwcn_failed_login_' . $ip_address . '_' . $username;
// 失敗カウントと時間を削除
delete_option($failed_login_key);
delete_option($failed_login_key . '_time');
}
add_action('wp_login', 'pwcn_reset_failed_login_count', 10, 2);
特に変更することはないと思いますが、コード中の「初期値は3回失敗まで」「分数を指定」でコメントされている行の値は好みで指定しなおしてください。個人的には回数はそのまま、ロックアウト時間はもっと長くてもいいのかなと思います。
また「ロックアウト中のメッセージ」の部分はロックアウト時に表示されるメッセージで、コードでは「ログイン試行回数を超えました」としていますが、個人的にはあまり理由を述べるのもどうかと思いますので何かいいものへ変更したほうがいいかも知れません。
コードの簡易解説
冒頭では簡易的に書きましたが、もう少し機構を掘り下げて解説します。もう動作したからいいよという方は見る必要はないでしょう(笑)。
以下が前半のプログラムに書いている流れです。
- ログイン画面から「ログイン」ボタンを押した時(ログイン動作を行った時)に、ログインに失敗したらIPアドレスとユーザー名を含めた一意のオプション行を追加し、失敗した回数をデータベースのoptionテーブルに追加
- 設定した試行回数に達した次のログイン動作でIPアドレスとユーザー名を含め、ロックアウト時間を値として指定した一意のオプション行を追加
- ロックアウト時間が記録されているIPアドレスかとユーザー名が合致する人がロックアウト時間内にログイン画面を表示しようとすると、拒否メッセージのみを表示
- ロックアウト時間が経過した次のログイン画面アクセスで、オプションを削除
ここまでのコード(コードでいうpwcn_limit_login_attemptsをinitへフックさせるまで)のままでは一度でも失敗したIPアドレスとユーザー名の組み合わせが永遠にoptionsテーブルに残ってしまい、ユーザー数の多いサイトでは不要な行が増殖していってしまうので、後半のコード(pwcn_reset_failed_login_count)でログインに成功したらそのIPアドレスとユーザー名の組み合わせのオプション行を削除するようにして、optionsテーブルを極力汚さないようにしています。
以上、あえてセキュリティに関わることですので文章で解説をしました。この説明でふむふむ..と理解できない方がコピペで実装するのは危険だと思いますので、素直にどなたかが作成した公式上のプラグインを使用するようにしてください。
ちなみに有名処では以下のようなプラグインがありますよ。
コメントを残す