wp-plugin-kashiwazaki-pattern-lock

A WordPress plugin that adds a 9-dot pattern lock to the standard login screen, requiring the correct pattern in addition to the username and password.

PHP ★ 0 🕔 0 GNU General Public License v2.0

Kashiwazaki Pattern Lock

WordPress
PHP
License
Version

WordPress 標準のログイン画面に、9 点をなぞるパターンロック認証を追加するプラグインです。ユーザー名・パスワードに加えて、サイト共通のパターンが一致したときだけログインを許可します。


1. できること

  • WordPress 標準のログイン画面(wp-login.php)に、3×3 の 9 点パターン入力欄を自動で表示します(ショートコード不要)。
  • 管理者は管理画面「Kashiwazaki Pattern Lock」(管理メニュー位置 81)で、サイト共通のパターンを 1 つ設定・変更できます。
  • PC ではマウス、スマートフォン・タブレットでは指でなぞって入力できます。
  • 選んだ点と、点を結ぶ線を画面に表示します。
  • 入力したパターンを消して、最初から入力し直せます(「入力を消す」ボタン、Esc キー)。
  • キーボードでも入力できます(点へ Tab で移動、矢印キーで点の移動、Enter / Space で選択、Backspace で 1 点戻す、Esc でクリア)。
  • ユーザー名・パスワード・パターンのすべてが正しいときだけログインを許可します。
  • パターンが未入力・間違いの場合はログインを拒否し、日本語のエラーメッセージを表示します。
  • 連続して認証に失敗すると、一定時間ログインを制限します(回数と時間は管理画面で設定)。
  • パターンは平文で保存せず、WordPress の wp_hash_password() でハッシュ化して保存します(WordPress 6.8 以降は bcrypt、それより前の版は WordPress 標準の phpass)。

2. 設置方法

  1. wp-plugin-kashiwazaki-pattern-lock フォルダを wp-content/plugins/ に置きます。
  2. 管理画面の「プラグイン」一覧で Kashiwazaki Pattern Lock を有効化します。
  3. 有効化すると 初期設定画面 が自動で開きます(開かない場合は左メニューの Kashiwazaki Pattern Lock、またはプラグイン一覧の「初期設定」リンクから開けます)。

有効化した直後はパターンが未設定のため、ログインは WordPress 標準のユーザー名・パスワードだけで行えます(設定するまでログインを妨げません)。

3. パターンの設定

はじめて設定するとき(初期設定画面)

パターンが未設定の間は、管理画面に 初期設定 の画面だけが表示されます。

  1. 「1. 新しいパターン」で 4 点以上をなぞります。
  2. 「2. 確認用パターン」で、同じ順番でなぞります。
  3. 「パターンを保存して開始」を押すと設定は完了です。

設定すると画面が管理画面(変更・解除・ログイン制限の設定)に切り替わり、次回のログインからパターンが必要になります。

設定を変更するとき(管理画面)

  1. 管理画面の Kashiwazaki Pattern Lock を開きます。
  2. 「パターンの変更」の「パターンを変更する」を開き、新しいパターンを 2 回入力します。
  3. 「パターンを保存」を押します。

パターンの決まり:

  • 4 点以上を使います。
  • 同じ点は 1 つのパターン内で 2 回使えません。
  • まだ選んでいない点を飛び越えて線を引いた場合、途中の点も選んだものとして扱います(例: 1 → 3 となぞると 2 も選ばれ、1 → 2 → 3 になります)。この補完は画面側とサーバー側の両方で同じ規則で行います。
  • 点をなぞる順番が違えば別のパターンです。
  • 点が多いほど推測されにくくなります。6 点以上を推奨します(4 点のパターンは組み合わせが少なく、総当たりに弱いためです)。

設定後は、次回のログインからパターンが必要になります。設定を変更すると、その場で新しいパターンに切り替わります。

パターンの解除

管理画面の「パターンの解除」で「上記を確認しました」にチェックを入れて「パターン設定を解除」を実行すると、パターンが消え、ログインは標準のユーザー名・パスワードだけに戻ります。

4. セキュリティ

  • サーバー側での検証: パターンの正誤は必ず PHP 側(authenticate フィルター)で判定します。画面側の JavaScript は入力の見た目と使い勝手のためのもので、判定には使っていません。
  • 保存方法: パターンは wp_hash_password() でハッシュ化して wp_options に保存します。平文は保存しません。検証は wp_check_password() で行います。
  • 入力値の検証と出力のエスケープ: 受け取る値は「1〜9 をカンマで区切ったもの」だけを許可し、それ以外はすべて拒否します。画面に出す値は esc_html() / esc_attr() / esc_url() でエスケープしています。
  • 管理画面の保護: 設定の保存・解除は、manage_options 権限の確認と nonce 検証(check_admin_referer())を行っています。
  • ログイン制限: 同じ IP アドレスとユーザー名の組み合わせで、設定した回数だけ失敗すると、設定した時間だけログインを制限します。あわせて、同じ IP アドレスからの失敗が設定回数の 10 倍(最低 50 回)に達した場合も制限します。これは 1 つの IP から多数のユーザー名を順に試す行為を止めるためです。
    • 失敗回数は専用テーブル({接頭辞}kashiwazaki_pattern_lock_attempts)に保存し、1 本の SQL で加算します。同時に失敗が起きても回数が失われません。
    • 制限の期限は「上限に達した時点から」数えます。また、ログインに成功すると、その IP アドレス+ユーザー名の失敗回数は消えます。
  • URL とログに残さない: パターンはログインフォームの POST 本文(hidden フィールド)だけで送ります。URL のクエリにも、WordPress のログにも書きません。エラーメッセージや管理画面の通知にもパターンの内容は含めません。
  • CSRF: ログイン自体は WordPress 標準のしくみ(testcookie・認証 Cookie)に従います。管理画面の操作は nonce で保護しています。

パターンの強度についての注意

パターンは 9 点から選ぶため、パスワードに比べると組み合わせが少ない方式です。ハッシュ化とログイン制限で総当たりは防げますが、データベースの内容が外部に漏れた場合、短いパターン(特に 4 点)は比較的早く推測され得ます。6 点以上を設定し、パスワードにも十分な強度のものを併用してください。

5. 対応範囲と制限(重要)

パターン認証が働くのは WordPress 標準のログイン画面(wp-login.php の通常ログイン)だけ です。次の経路はパターンの対象外で、これまでどおりユーザー名とパスワードだけで認証されます。

経路 パターンの要否 備考
標準ログイン画面(wp-login.php) 必要 本プラグインの対象
ログイン済みの認証 Cookie 対象外 すでにログインしている利用者はそのまま操作できます
REST API(wp-json) 対象外 認証 Cookie またはアプリケーションパスワードで認証されます
アプリケーションパスワード 対象外 「プロフィール」画面で発行したパスワードで認証されます
XML-RPC 対象外 ユーザー名とパスワードで認証されます
パスワード再設定(wp-login.php?action=lostpassword / resetpass) 対象外 メールのリンクから再設定できます
ユーザー登録(wp-login.php?action=register) 対象外 登録後のログイン時にパターンが必要です
保護された投稿のパスワード入力(action=postpass) 対象外 投稿のパスワードであり、ログインではありません
別プラグインが独自に用意したログイン画面・API 対象外 その画面が wp_signon() を直接呼ぶ場合、パターンは検証されません

リバースプロキシ・CDN の背後で使うとき(ログイン制限の IP アドレス)

ログイン制限は、サーバーが申告する接続元の IP アドレス(REMOTE_ADDR)で失敗を数えます。リバースプロキシや CDN の背後では、REMOTE_ADDR がプロキシの IP アドレスになり、全員が同じ IP アドレスに見えます。その状態では、誰か 1 人が失敗を重ねる(既定では 50 回)だけで、同じプロキシ経由の全員(管理者を含む)が一定時間ログインできなくなります。

Cloudflare は、設定なしで対応しています。 REMOTE_ADDR が Cloudflare の IP アドレスの範囲(Cloudflare が公開している一覧)に入っている通信に限り、Cloudflare が付ける本当の接続元の IP アドレス(CF-Connecting-IP)を使います。範囲の外から届いた通信のヘッダーは、訪問者が自分で書けるため無視します。Cloudflare の IP アドレスの範囲は、Cloudflare の公式 API から自動で取得します(下の「Cloudflare の IP アドレスの範囲の自動取得」)。取得できないあいだは、プラグインに内蔵した一覧(2026-10-28 に公式の一覧から取得したもの)を使います。範囲の外から届いた通信は REMOTE_ADDR のまま扱います(偽装される側には倒れません)。管理画面の「ログイン制限の設定」にある「Cloudflare 経由のとき、本当の接続元の IP アドレスを使う」のチェック(既定はオン)で、切り替えられます。コードで決めたいときは、フィルター kashiwazaki_pattern_lock_trust_cloudflare で true か false を返してください(フィルターの値が、チェックより優先されます)。

Cloudflare の IP アドレスの範囲の自動取得

  • 取得先: Cloudflare の公式 API(https://api.cloudflare.com/client/v4/ips。認証は不要。公式の説明)。
  • タイミング: 1 日 1 回、WP-Cron で取得します。ログインの処理の途中で取得することはありません。
  • 送る情報: ありません(サイトの URL・ユーザー名・IP アドレスなどは送りません。プラグイン名と版だけを User-Agent に付けます)。サービスの利用規約・プライバシーポリシーは Cloudflare のものです。
  • 取得した内容の検査: 正規の CIDR で、広すぎず(IPv4 は /12 以上、IPv6 は /28 以上)、狭すぎず(IPv4 は /24 まで、IPv6 は /48 まで。1 つの IP アドレスだけの範囲は使いません)、予約された範囲(プライベート・ループバック・ドキュメント用など)と重ならず、重複や重なりがなく、件数が妥当な一覧だけを使います。1 件でも不正なら全部使わず、前の一覧を残します。保存した値も、読むときにもう一度検査します。
  • この検査の限界: 危険な形や範囲を除くための検査で、一覧が Cloudflare のものであることの証明ではありません。真正性は、公式 API への HTTPS 接続(証明書の検証)と、サイトのデータベースの保護に依ります。
  • 取得できないとき・古いとき: 取得に失敗しても、前に取得した一覧(取得から 45 日以内)か、内蔵の一覧を使います。45 日以上更新できないときは、内蔵の一覧に戻ります。管理画面「ログイン制限の設定」に、取得元と最終更新(失敗したときは理由)が出ます。
  • 止めたいとき: 管理画面の「Cloudflare 経由のとき、本当の接続元の IP アドレスを使う」をオフにすると、取得しません。コードで決めるときは、フィルター kashiwazaki_pattern_lock_auto_update_cloudflare_ranges で false を返してください。範囲そのものを差し替えるときは、フィルター kashiwazaki_pattern_lock_cloudflare_ranges を使います。

Cloudflare 以外のリバースプロキシ・CDN の背後では、フィルター kashiwazaki_pattern_lock_client_ip で、プロキシが付ける本当の接続元の IP アドレスを返してください。テーマの functions.php か、独自のプラグイン(mu-plugins など)に書きます。

// 例: 自分のリバースプロキシの背後(プロキシが付ける X-Real-IP を使う)
add_filter(
	'kashiwazaki_pattern_lock_client_ip',
	function ( $ip ) {
		if ( ! empty( $_SERVER['HTTP_X_REAL_IP'] ) ) {
			return trim( wp_unslash( $_SERVER['HTTP_X_REAL_IP'] ) );
		}

		return $ip;
	}
);
  • フィルターが返した値が正しい IP アドレス(IPv4・IPv6)の文字列でなければ、使わずに REMOTE_ADDR に戻します。
  • 上の例は、プロキシを通さずにサイトへ直接アクセスできない構成(プロキシ以外からの接続を遮断している)が前提です。直接アクセスできる状態で X-Real-IP を信用すると、訪問者がこのヘッダーを自分で付けて IP アドレスを偽装できます。
  • 信頼できる経路の値だけを返してください。 プロキシを通さずにサイトへ直接アクセスできる環境で、訪問者が自由に書き換えられるヘッダー(X-Forwarded-For など)をそのまま返すと、IP アドレスを偽装して失敗の数を避けられてしまいます。
  • フィルターを使わないときの動作は、これまでと同じです(REMOTE_ADDR だけを見ます)。

そのため、「パターンだけでサイト全体の認証が固くなる」わけではありません。パターンは標準ログイン画面の追加の関門であり、REST API・XML-RPC・アプリケーションパスワードは別途、停止する・制限するなどの対策を検討してください(例: xmlrpc_enabled フィルターで XML-RPC を無効化する、不要なアプリケーションパスワードを削除する)。

競合しうるもの

  • ログイン画面を独自のデザインに置き換えるプラグイン(カスタムログインページ系)を使う場合、その画面が login_form アクションを呼ばないとパターン入力欄が出ません。その状態でもサーバー側の検証は働くため、ログインできなくなります。導入前に必ずテストしてください。
  • 2 要素認証(TOTP など)のプラグインとは併用できます。どちらも authenticate フィルターを使いますが、パターンは優先度 30、ログイン制限は優先度 100 で動きます。
  • wp-login.php の中で、別プラグインが独自の action(login_form_<action> のフック)で認証を行い、その処理が wp_authenticate() や wp_signon() を呼ぶ場合、パターンの確認が働きます(action の値は判定に使いません)。その処理の画面にパターン入力欄が無いと、ログインできません。導入前に必ずテストしてください。
  • キャッシュ系プラグインの影響は受けません(wp-login.php は通常キャッシュされません)。

JavaScript について

パターンの入力には JavaScript が必要です。JavaScript が無効な環境では入力欄を操作できないため、ログインできません(画面にその旨を表示します)。

6. 復旧手順(パターンを忘れた・設定を誤ってログインできない)

管理画面に入れない場合は、FTP クライアントやサーバーのファイルマネージャーで次の作業を行います。

手順 A: プラグインを無効化する(おすすめ)

  1. FTP などで wp-content/plugins/ を開きます。
  2. wp-plugin-kashiwazaki-pattern-lock フォルダの名前を変更します。例: wp-plugin-kashiwazaki-pattern-lock.disabled
  3. WordPress はプラグインファイルを見つけられなくなり、そのプラグインを自動的に無効化します。
  4. wp-login.php を開くと、WordPress 標準のユーザー名・パスワードだけでログインできる状態に戻ります。
  5. ログイン後、管理画面の「プラグイン」一覧を開き、無効化されたことを確認します。パターンを設定し直す場合は、フォルダ名を元に戻して再度有効化し、設定画面で新しいパターンを保存してください。

手順 B: 設定を直接消す(サーバーの管理画面がある場合)

データベースを直接操作できる場合(phpMyAdmin など)は、wp_options テーブルの次の行を削除しても復旧できます。

  • option_name = 'kashiwazaki_pattern_lock_settings'

この行を削除すると、パターンは未設定として扱われ、ログインは標準認証に戻ります。ログイン制限の設定(失敗の上限回数・制限する時間)は別の行に保存されているため、これらも既定値に戻したいときは、次の行も削除してください。

  • option_name = 'kashiwazaki_pattern_lock_limits'

注意

  • フォルダを削除すると、WordPress の「削除」処理(uninstall.php)が動かない限り設定はデータベースに残ります。再インストールすると以前のパターンがそのまま復活します。作り直す場合は、管理画面から削除するか、手順 B で設定を消してください。
  • 失敗回数の制限中は、正しいパターンを入力してもログインできません。設定した時間(既定 15 分)が経つまで待つか、手順 A で無効化してください。

7. アンインストール

管理画面の「プラグイン」一覧から 削除 すると、uninstall.php が動き、設定(パターンのハッシュ、失敗回数の設定)、失敗回数のテーブル、一時データを削除します。マルチサイトでは各サイト分を削除します。

8. ファイル構成

wp-plugin-kashiwazaki-pattern-lock/
├── wp-plugin-kashiwazaki-pattern-lock.php   プラグイン本体(定義・読み込み)
├── includes/
│   ├── kashiwazaki-pattern-lock-pattern.php   パターンの正規化・ハッシュ・検証
│   ├── kashiwazaki-pattern-lock-storage.php   失敗回数のテーブル
│   ├── kashiwazaki-pattern-lock-rate-limit.php 連続失敗の記録とログイン制限
│   ├── kashiwazaki-pattern-lock-widget.php    9点ウィジェットの描画
│   ├── kashiwazaki-pattern-lock-login.php     ログイン画面への組み込みと認証
│   └── kashiwazaki-pattern-lock-admin.php     設定画面と保存処理
├── assets/
│   ├── css/kashiwazaki-pattern-lock-widget.css
│   ├── css/kashiwazaki-pattern-lock-admin.css
│   └── js/kashiwazaki-pattern-lock-widget.js
├── languages/
├── uninstall.php
├── readme.txt
├── README.md
├── CHANGELOG.md
└── LICENSE

9. 動作環境

  • WordPress 6.0 以上(開発・確認は 6.9.4)
  • PHP 7.4 以上
  • モダンブラウザ(Chrome / Firefox / Safari / Edge の現行版)。スマートフォンは iOS Safari・Android Chrome を想定しています。

10. 変更履歴

CHANGELOG.md を参照してください。