EY-Office ブログ

EY-Officeのお問い合わせフォームにreCAPTCHAを導入しました

先週、EY-Officeのお問い合わせフォームにreCAPTCHAを導入しました。
実は最近、お問い合わせフォームからのセールス系のスパムが増えていて少し困っていたのです。

reCAPTCHA Gemini 2.5 Flash Imageが生成した画像を使っています

EY-Officeのお問い合わせフォームの歴史

スパム対処なし

EY-Officeのホームページを作った当初からお問い合わせフォームを設けていましたが、当時はフォームへのスパムは少なくスパム対処はしていませんでした。

Gmailのスパムフィルター

そのうちに、海外からのスパムが送られてくるようになりました。そこでフォーム内容を受け取るメールをGmailにして、Gmailのスパム・フィルターを利用する事にしました。スパムはかなり減りました。

日本語のお問い合わせのみ受け付ける

さらに時間が経つと、またスパムが増えて来ました。スパムは海外のものが多いので、問い合わせの内容に日本語がない問合せは受け付けないようにソフトを修正しました。これで再度スパムは減りました。

reCAPTCHA導入を考える

しかし、ここに来て日本語のスパムが届くようになりました。SEO業者、経営コンサル、営業代行業者・・・の宣伝がフォームに送られてきます。
いよいよreCAPTCHAを導入しないと行けないのかな? と思うようになりました。

reCAPTCHAとは

皆さまも、Webサービスのログイン等でreCAPTCHAを体験されていると思います。下の画像のような判読しづらい文字を入力する方式や、複数画像の中から指定された物が写った画像を選択する方式が知られています。
今回、reCAPTCHAを導入するために調べてみたところ、以下のようにバージョン1〜3があるようなので、AIにまとめてもらいました。

reCAPTCHA v1の概要

  • 画像内の歪んだ文字や数字を人間が判読して入力する「文字認証」方式でした。
  • ボットによる迂回が増え、文字が判読しにくい等の課題が多く、2018年に提供が終了しています。

Google 「reCAPTCHAのデザインをカスタマイズする」より

reCAPTCHA v2の特徴

  • 「私はロボットではありません」チェックボックスや、画像選択テストによるチャレンジ認証方式。
    • チェックボックス:クリックして判定、怪しい場合は画像選択チャレンジ。
    • Invisible(非表示):ユーザー操作なくリクエストごとに自動判定し、怪しい場合のみ画像認証。
  • 判定は「OK/NG」の二値で、ユーザーの明示的な操作を求めるためやや手間がかかります。

Figumaコミュニティ reCAPTCHA Mockupより

reCAPTCHA v3の特徴

  • コアベース認証方式で、ユーザーのページ内での行動などをAIが分析し、0.0〜1.0のスコア(人間度)を返します。
  • フォーム送信時も含めユーザー操作不要、見た目にはバッジが表示されることがあるのみ。
  • スコア結果に応じてアプリ側で処理(例:追加認証や確認)が可能。
  • ユーザー負担なくUX重視、しかし開発者の設計次第でセキュリティレベルの調整が必要です。

reCAPTCHAの導入方法

reCAPTCHA v3の導入方法は、公式ページのガイドに書かれています。クライアント(Web)側に付いてはサンプルコードが書かれていますが、サーバー側は説明のみでサンプルコードはありません。
ネットを検索したり、AIにたずねるとサーバー側のサンプルコードが出てきます。ただし出てきたサンプルコードはシンプルでないものが多いですね。

EY-Officeの、お問い合わせフォームはPHPで書かれていますが、reCAPTCHA v3導入で追加したコードを書きます。

クライアント側

クライアント側は公式ページのガイドに書かれているコードそのままです、簡単です。
RECAPTCHA_SITE_KEYRECAPTCHA_SECRET_KEY は、公式ページの新しいサイトを登録するで生成します。

  • ① GoogleのreCAPTCHAのJavaScriptを読み込みます
  • ② Submitボタンに公式ページのガイドにあるパラメーターを追加します
<?php

・・・

define("RECAPTCHA_JS_URL", "https://www.google.com/recaptcha/api.js");
define("RECAPTCHA_SITE_KEY", "・・・・");
?>

・・・

<script src="<?=RECAPTCHA_JS_URL?>"></script>    // ← ①

・・・

<form method="post" ・・・ >

・・・

  <button type="submit" class="g-recaptcha pure-button pure-button-primary"
          data-sitekey="<?=RECAPTCHA_SITE_KEY?>"
          data-action="submit" data-callback="onSubmit">送信</button>   // ← ②
</form>

サーバー側

公式ページには解説がありますが、コードは無かったのでネットの情報から作りました

  • ① クライアントから情報(トークン)をGoogleのAPIを使い検証結果を受け取ります
    • クライアントからは'g-recaptcha-responseにはreCAPTCHAのJavaScriptが生成したトークンが渡っています
    • file_get_contentsでAPI呼出しを行っています
    • APIのレスポンスは公式ページに解説があります
  • ② APIレスポンスでスパムか判定
    • $recaptcha_verify_result['success']はクライアントからのトークンが有効かをチェックしています
    • $recaptcha_verify_result['score']は人間度で、0.0なら完全なスパム、1.0なら人間の入力です
    • ここでは0.5で判定していますが、この値を変える事でスパム判定の厳しさを調整できます
<?php

・・・・

define("RECAPTCHA_VERIFY_URL", "https://www.google.com/recaptcha/api/siteverify");
define("RECAPTCHA_SECRET_KEY", "・・・・");

if ($_SERVER["REQUEST_METHOD"] == "POST") {
  // ↓ ①
  $recaptcha_response = $_POST['g-recaptcha-response'];
  $recaptcha_verify_url = RECAPTCHA_VERIFY_URL . "?secret=" .
    RECAPTCHA_SECRET_KEY . "&response=" . $recaptcha_response;
  $recaptcha_verify_response = file_get_contents($recaptcha_verify_url);
  $recaptcha_verify_result = json_decode($recaptcha_verify_response, true);
  $recaptcha_score = $recaptcha_verify_result['score'] ?? -1;

  // ↓ ②
  if($recaptcha_verify_result['success'] && $recaptcha_score > 0.5) {
    // スパムではない場合
    ・・・・
} else {
    // reCAPTCHAの認証に失敗
    recaptcha_error_log();
}

・・・・

動作しているかの検証

これは難し課題ですね。😅
私が人手で入力した時には、人間度のスコアは1.0でした。そこで、ブラウザーをコードで操作できるツールPlaywrighを使いテストしてみました。

コードは以下のようになります(テストコードのスタイルになっています)・

import { test, expect } from '@playwright/test';

test('Post contact form', async ({ page }) => {
  await page.goto('https://・・・・・・');
  await page.fill('input[name="name"]', 'テスト太郎');
  await page.fill('input[name="email"]', '・・・@・・・');
  await page.fill('textarea[name="body"]', 'テストですが、よろしくお願いいたします。');
  await page.click('button[type="submit"]');
  await expect(page.getByText('お問い合わせありがとうございます。')).toBeVisible();
});

このコードを実行したときのスコアは0.7でした。今回のコードの閾値ではスパムになりませんね。😅

スコアの値をログファイルに残すようにしたので、観察しスパムに閾値を変更して行きたいと思います。

まとめ

今回、reCAPTCHAに付いて調べるまで、判読しづらい文字を入力する、または複数画像の中から選択する方式しか知らなっかたので、気軽にお問い合わせして欲しいEY-Officeのお問い合わせへの、reCAPTCHAの導入には躊躇していました。
しかし、reCAPTCHA v3は利用者の余計な操作は不要なので、このような用途には最適なサービスだと思います。😃

また、お問い合わせフォームのエラーログを見ていると、フォームを使わずに直接POSTしてくるスパムがある事に気が付きました。これはフォームに何らかのトークンを埋め込みサーバー側でチェックすれば対応出来そうですが、reCAPTCHA導入する方が簡単ですね。😃

- about -

EY-Office代表取締役
・プログラマー
吉田裕美の
開発者向けブログ