制作Note

Contact Form 7のスパム対策完全ガイド:3層防御でスパムを撃退

はじめに

お問い合わせフォームへのスパムメール、本当に厄介ですよね。

Google reCAPTCHAの有料化をきっかけに、Cloudflare Turnstileへ移行された方も多いと思います。しかし、Turnstileだけでは防ぎきれないスパムがあるのも事実です。

そこで本記事では、3つの対策を組み合わせた「3層防御」をご紹介します。

なぜ3層防御が必要なのか

それぞれの対策には得意・不得意があります。

対策 防げるもの 防げないもの
Cloudflare Turnstile 自動化されたボット 人間によるスパム
ハニーポット 単純なボット 賢いボット、手動スパム
URL入力禁止 URLを含むスパム全般 URLを含まないスパム

1つの対策で完璧に防ぐことは不可能です。しかし、3つを組み合わせることで、それぞれの弱点を補い合い、ほぼ全てのスパムをブロックできます。

3層防御の仕組み

送信ボタンクリック
【第1層】Turnstile → ボットを自動判定
↓ 通過
【第2層】ハニーポット → 単純ボットを検出
↓ 通過
【第3層】URL禁止 → スパム内容をチェック
↓ 通過
✅ 正常なお問い合わせとして受信

実装方法

第1層:Cloudflare Turnstile

Turnstileの導入方法は割愛しますが、プラグイン「Simple Cloudflare Turnstile」を使えば簡単に設定できます。

第2層・第3層:functions.phpへの追記

以下のコードをfunctions.phpに追記してください。

<?php
/**
* ============================================
* Contact Form 7 スパム対策(3層防御)
* - 第2層:ハニーポットフィールド
* - 第3層:URL入力禁止
* ============================================
*/

/**
* --------------------------------------------
* 第2層:ハニーポットフィールド
* --------------------------------------------
* ボットはフォームの全項目を自動入力する傾向があります。
* 人間には見えない隠しフィールドを設置し、
* 入力があった場合はスパムと判定します。
*/

// ハニーポット用のショートコードタグを登録
add_action('wpcf7_init', 'add_honeypot_field_to_cf7');
function add_honeypot_field_to_cf7() {
  wpcf7_add_form_tag('honeypot', 'honeypot_shortcode_handler');
}

// ハニーポットフィールドのHTML出力
function honeypot_shortcode_handler($tag) {
  return '<div style="position:absolute;left:-9999px;top:-9999px;" aria-hidden="true">
      <label for="website_url">ウェブサイト(入力しないでください)</label>
      <input type="text" id="website_url" name="website_url" tabindex="-1" value="" autocomplete="off">
      <label for="user_phone">電話番号確認(入力しないでください)</label>
      <input type="text" id="user_phone" name="user_phone" tabindex="-1" value="" autocomplete="off">
  </div>';
}

// ハニーポットのバリデーション
add_filter('wpcf7_validate', 'validate_honeypot_cf7', 10, 2);
function validate_honeypot_cf7($result, $tags) {
  if (!empty($_POST['website_url']) || !empty($_POST['user_phone'])) {
      $result->invalidate('honeypot', 'エラーが発生しました。しばらくしてから再度お試しください。');
      error_log('Spam detected via honeypot from IP: ' . $_SERVER['REMOTE_ADDR']);
  }
  return $result;
}

/**
* --------------------------------------------
* 第3層:URL入力禁止
* --------------------------------------------
* スパムメールのほとんどはURLを含んでいます。
* URL入力を禁止することで、スパムの目的達成を阻止します。
*/

// テキストフィールドにフィルターを追加
add_filter('wpcf7_validate_text', 'validate_no_urls_in_text', 20, 2);
add_filter('wpcf7_validate_text*', 'validate_no_urls_in_text', 20, 2);
add_filter('wpcf7_validate_textarea', 'validate_no_urls_in_textarea', 20, 2);
add_filter('wpcf7_validate_textarea*', 'validate_no_urls_in_textarea', 20, 2);

// URLを許可するフィールド名を定義
function get_url_allowed_fields() {
  return array(
      'url',       // 会社URL用フィールドなど
      'website',   // Webサイト用フィールドなど
  );
}

// テキストフィールドのURL検証
function validate_no_urls_in_text($result, $tag) {
  $name = $tag->name;
  
  if (in_array($name, get_url_allowed_fields())) {
      return $result;
  }
  
  $value = isset($_POST[$name]) ? trim($_POST[$name]) : '';
  
  if (check_for_url_patterns($value)) {
      $result->invalidate($tag, 'URLやリンクを含めることはできません。');
  }
  
  return $result;
}

// テキストエリアのURL検証
function validate_no_urls_in_textarea($result, $tag) {
  $name = $tag->name;
  
  if (in_array($name, get_url_allowed_fields())) {
      return $result;
  }
  
  $value = isset($_POST[$name]) ? trim($_POST[$name]) : '';
  
  if (check_for_url_patterns($value)) {
      $result->invalidate($tag, 'URLやリンクを含めることはできません。');
  }
  
  return $result;
}

// URLパターンの検出
function check_for_url_patterns($value) {
  if (empty($value)) {
      return false;
  }
  
  $patterns = array(
      '#https?://#i',
      '#www\.[a-z0-9-]+\.[a-z]{2,}#i',
      '#[a-z0-9-]+\.(com|net|org|info|biz|co\.jp|jp|cn|ru|tk|ml|ga|cf|gq)\b#i',
      '#bit\.ly|tinyurl|goo\.gl|ow\.ly#i',
      '#[a-z0-9-]+\.link|\.click|\.top#i',
  );
  
  foreach ($patterns as $pattern) {
      if (preg_match($pattern, $value)) {
          return true;
      }
  }
  
  return false;
}

Contact Form 7側の設定

フォーム編集画面で、ハニーポット用のショートコードを追加します。

[honeypot]

[text* your-name placeholder "お名前"]
[email* your-email placeholder "メールアドレス"]
[textarea* your-message placeholder "お問い合わせ内容"]
[submit "送信"]

[honeypot]は画面に表示されませんが、必ずフォーム内に記述してください。

各対策の詳細解説

第1層:Cloudflare Turnstile

Googleの「私はロボットではありません」に代わる認証システムです。

メリット

  • 無料で利用可能
  • ユーザーの操作不要(多くの場合)
  • プライバシーに配慮した設計

限界

  • 人間が手動で送信するスパムは防げない
  • 高度なボットは突破する可能性がある

第2層:ハニーポットフィールド

人間には見えない「罠」のフィールドです。

仕組み

  1. 画面外に隠しフィールドを設置
  2. 人間には見えないので入力されない
  3. ボットは全項目を埋めようとする
  4. 入力があればスパムと判定

メリット

  • ユーザー体験を損なわない
  • 実装が簡単

限界

  • 賢いボットは隠しフィールドを無視する
  • CSSの隠し方を検出するボットもいる

第3層:URL入力禁止

スパムの「目的」を潰す対策です。

なぜ効果的か

スパムの目的は、ほぼ確実に「悪意のあるサイトへの誘導」です。そのため、スパムメールには必ずURLが含まれています。URL入力を禁止すれば、スパマーは目的を達成できません。

メリット

  • ボット・手動スパム両方に効果的
  • スパムの根本的な目的を阻止

注意点

  • 正規ユーザーがURLを送信できなくなる
  • 必要に応じて許可リストを設定する

カスタマイズ

URL許可フィールドの追加

会社URLなど、特定のフィールドでURLを許可したい場合は、get_url_allowed_fields()に追加します。

function get_url_allowed_fields() {
  return array(
      'url',
      'website',
      'company-url',  // 追加
      'reference',    // 追加
  );
}

検出ドメインの追加

スパムでよく使われるドメインを追加できます。

'#[a-z0-9-]+\.(com|net|org|info|biz|co\.jp|jp|cn|ru|tk|ml|ga|cf|gq|xyz|pw|cc)\b#i',

エラーメッセージの変更

$result->invalidate($tag, 'お問い合わせ内容にURLを含めることはできません。参照サイトがある場合はサイト名でお知らせください。');

導入時の注意点

正規ユーザーへの配慮

URL入力禁止により、正規ユーザーが「参考URL」などを送信できなくなります。

対策例

  • フォームに「URLは入力できません」と明記する
  • 「参照サイトがある場合はサイト名をご記入ください」と案内する
  • URL入力用の専用フィールドを用意し、許可リストに追加する

テスト方法

導入後は必ずテストしてください。

  1. 正常な内容で送信 → 送信成功を確認
  2. URLを含めて送信 → エラー表示を確認
  3. 許可フィールドにURL入力 → 送信成功を確認

まとめ

対策 役割
第1層 Cloudflare Turnstile ボットを自動判定
第2層 ハニーポット 単純ボットを検出
第3層 URL入力禁止 スパム内容をブロック

この3層防御により、スパムメールを大幅に削減できます。

それぞれ単独では限界がありますが、組み合わせることで弱点を補い合い、強固な防御が実現できます。

導入はfunctions.phpへのコード追記と、フォームへの[honeypot]追加だけです。ぜひお試しください。