2026年5月20日
2026年5月20日
WordPressのフィッシング攻撃からアカウントを守る方法
はじめに
フィッシング攻撃では、攻撃者がWordPress管理者を偽のログインページに誘導してパスワードを盗むか、ソーシャルエンジニアリングで認証情報を取得します。2要素認証(2FA)・異常ログイン検出・強力なパスワードポリシーを組み合わせることで、フィッシングで認証情報が盗まれても不正アクセスを防げます。
症状・原因
- WordPressのログイン画面を模した偽サイトへの誘導メールが届いた
- パスワードを変更していないのに「パスワードが変更されました」の通知が届いた
- 知らない場所・デバイスからのログインがあった
- フィッシングメールに記載されたリンクをクリックしてしまった
解決手順
ステップ1:フィッシングの被害を確認する
# 最近のログイン履歴を確認(アクティビティログプラグイン使用時)
wp eval "
global \$wpdb;
\$logins = \$wpdb->get_results(\"
SELECT * FROM {\$wpdb->prefix}activity_log
WHERE action IN ('login_success', 'login_failed')
ORDER BY created_at DESC LIMIT 30
\");
foreach (\$logins as \$log) {
echo \$log->created_at . ' | ' . \$log->ip_address . ' | ' . \$log->message . PHP_EOL;
}
"
# 管理者アカウントの最終ログイン時刻を確認
wp user get 1 --fields=ID,user_login,user_email
# 不審なセッションが存在するか確認
wp eval "
\$users = get_users(['role' => 'administrator']);
foreach (\$users as \$user) {
\$sessions = get_user_meta(\$user->ID, 'session_tokens', true);
echo \$user->user_login . ': ' . count((array)\$sessions) . ' sessions' . PHP_EOL;
}
"
# 不審なセッションを即座に全削除
wp eval "
\$users = get_users(['role' => 'administrator']);
foreach (\$users as \$user) {
\$manager = WP_Session_Tokens::get_instance(\$user->ID);
\$manager->destroy_all();
echo 'Sessions cleared for: ' . \$user->user_login . PHP_EOL;
}
"
ステップ2:2要素認証(2FA)を設定する
# 2FA プラグインをインストール
wp plugin install two-factor --activate
# または WP 2FA プラグイン
wp plugin install wp-2fa --activate
// functions.php: 管理者に 2FA を強制する
// ① 管理者が 2FA を設定していない場合にリダイレクト
add_action('admin_init', function(): void {
if (!current_user_can('manage_options')) return;
if (defined('DOING_AJAX') && DOING_AJAX) return;
$user_id = get_current_user_id();
// Two Factor プラグインの 2FA 設定確認
if (class_exists('Two_Factor_Core')) {
$providers = Two_Factor_Core::get_enabled_providers_for_user(get_userdata($user_id));
if (empty($providers)) {
// 2FA 設定ページにリダイレクト(設定ページURL は環境によって異なる)
if (!isset($_GET['page']) || $_GET['page'] !== 'two-factor-user-settings') {
wp_redirect(admin_url('profile.php#two-factor-options'));
exit;
}
}
}
});
// ② ログイン成功時に通知メールを送信
add_action('wp_login', function(string $user_login, \WP_User $user): void {
// 管理者のみ通知
if (!user_can($user, 'manage_options')) return;
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
$ua = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
$time = current_time('Y-m-d H:i:s');
wp_mail(
$user->user_email,
'[WordPress] 管理者ログイン通知',
"以下のアクセスがありました。\n\n"
. "時刻: {$time}\n"
. "IP: {$ip}\n"
. "ブラウザ: {$ua}\n\n"
. "心当たりがない場合は、すぐにパスワードを変更し、全セッションを無効化してください:\n"
. admin_url('profile.php')
);
}, 10, 2);
ステップ3:強力なパスワードポリシーを強制する
// functions.php: パスワードポリシーの強制
// ① パスワード強度の検証
add_action('user_profile_update_errors', function(\WP_Error $errors, bool $update, \WP_User $user): void {
if (empty($_POST['pass1'])) return;
$password = $_POST['pass1'];
// 最低12文字
if (strlen($password) < 12) {
$errors->add('weak_password', 'パスワードは12文字以上にしてください。');
}
// 大文字・小文字・数字・記号を含む
if (!preg_match('/[A-Z]/', $password)) {
$errors->add('weak_password', 'パスワードに大文字を含めてください。');
}
if (!preg_match('/[a-z]/', $password)) {
$errors->add('weak_password', 'パスワードに小文字を含めてください。');
}
if (!preg_match('/[0-9]/', $password)) {
$errors->add('weak_password', 'パスワードに数字を含めてください。');
}
if (!preg_match('/[!@#$%^&*()_+\-=\[\]{}|;:,.<>?]/', $password)) {
$errors->add('weak_password', 'パスワードに記号を含めてください。');
}
// よく使われるパスワードをブロック
$common_passwords = ['password123', 'wordpress', 'admin123', 'letmein'];
if (in_array(strtolower($password), $common_passwords, true)) {
$errors->add('weak_password', 'このパスワードは使用できません。');
}
}, 10, 3);
// ② パスワードの有効期限(90日)
add_action('wp_login', function(string $login, \WP_User $user): void {
$last_changed = get_user_meta($user->ID, 'password_last_changed', true);
if (!$last_changed) {
update_user_meta($user->ID, 'password_last_changed', time());
return;
}
$days = (time() - (int)$last_changed) / DAY_IN_SECONDS;
if ($days > 90 && user_can($user, 'manage_options')) {
wp_redirect(admin_url('profile.php?password_expired=1'));
exit;
}
}, 10, 2);
ステップ4:不審なログインを検出してブロックする
// functions.php: 不審なログインパターンの検出
add_action('wp_login', function(string $login, \WP_User $user): void {
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$user_id = $user->ID;
// 前回ログインのIPを取得
$last_ip = get_user_meta($user_id, 'last_login_ip', true);
$last_country = get_user_meta($user_id, 'last_login_country', true);
// 現在のIPを保存
update_user_meta($user_id, 'last_login_ip', $ip);
update_user_meta($user_id, 'last_login_time', time());
// 前回と異なるIPからのログインを通知(管理者のみ)
if ($last_ip && $last_ip !== $ip && user_can($user, 'manage_options')) {
wp_mail(
get_option('admin_email'),
'[警告] 通常と異なるIPからのログイン',
"ユーザー: {$login}\n"
. "前回IP: {$last_ip}\n"
. "今回IP: {$ip}\n"
. "時刻: " . current_time('Y-m-d H:i:s') . "\n\n"
. "心当たりがない場合はパスワードを変更してください。"
);
}
}, 10, 2);
ステップ5:wp-login.php のURLをカスタマイズして偽サイト誘導を困難にする
// functions.php: ログインURLを変更してフィッシングを困難にする
// ※ WPS Hide Login プラグインを使用する方が簡単
// カスタムログインURL のスラッグ
define('CUSTOM_LOGIN_SLUG', 'my-secure-portal');
add_action('init', function(): void {
if (!defined('CUSTOM_LOGIN_SLUG')) return;
// カスタムログインスラッグへのアクセスを wp-login.php にルーティング
if (isset($_GET[CUSTOM_LOGIN_SLUG])) {
// 内部的に wp-login.php に渡す
}
// wp-login.php への直接アクセスをブロック
global $pagenow;
if ($pagenow === 'wp-login.php' && !isset($_GET[CUSTOM_LOGIN_SLUG])) {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
wp_redirect(home_url('/404'));
exit;
}
}
});
// ログインURLをカスタムURLに変更
add_filter('login_url', function(string $url): string {
return home_url('/' . CUSTOM_LOGIN_SLUG . '/');
}, 10);
注意事項
- 2要素認証を管理者に強制する前に、必ず自分のアカウントで2FAが正常に機能することを確認してください。設定を誤ると管理画面にアクセスできなくなります
- ログインURL変更後はWordPressパスワードリセットメール内のURLも変更されます。
lostpassword_urlフィルターでリセットURLも合わせて変更する必要があります - フィッシングメール内のリンクをクリックした可能性がある場合は、まず
wp config shuffle-saltsで全セッションを無効化し、管理者パスワードを変更してから2FAを設定してください
まとめ
フィッシング対策は①WP_Session_Tokens::destroy_all()で不審なセッションを全削除、②wp plugin install two-factorで2FAを設置・管理者に強制、③ログイン成功時にwp_loginフックでメール通知、④パスワードポリシー(12文字以上・大小数字記号)をuser_profile_update_errorsで強制、⑤通常と異なるIPからのログインを検出して管理者に通知します。