問い合わせフォームにreCAPTCHAを入れて送信できなくなったときの切り分け|キーは2つあり、片方だけ無効になる
問い合わせフォームにreCAPTCHAを入れて送信できなくなったときの切り分け|キーは2つあり、片方だけ無効になる
問い合わせフォームにスパム対策としてreCAPTCHAを設置したら、今度はフォームが送信できなくなった。送信ボタンを押しても何も起きない。あるいは、設置したはずなのにスパムが素通りしてくる――。reCAPTCHAまわりの不具合の相談は、だいたいこの2パターンのどちらかで持ち込まれます。
先に結論を書きます。reCAPTCHAが動かないとき、最初に疑うべきは「設定の種類」ではなく「キーの値」です。 v2かv3か、ドメイン登録が合っているか、といった設定項目を見直す前に、サイトに実際に入っているキーの文字列がGoogleの管理画面のものと一致しているかを確かめてください。原因の多くはそこにあります。
キーは2つで1組。だから「片方だけ無効」が起きる
reCAPTCHAのキーは1つではありません。サイトキーとシークレットキーの2つで1組です。
- サイトキー――ページのHTMLに出力される公開キー。ブラウザ側でトークンを取得するときに使う
- シークレットキー――サーバー側でトークンを検証するときに使う秘密のキー。ページには一切出力されない
この2つは管理画面から別々にコピーして、別々の入力欄に貼り付けます。つまり、コピペの機会が2回あるということです。片方を貼り間違える、古いキーが残ったまま片方だけ更新する、別サイト用のキーと取り違える――2回あるコピペのどちらか一方だけが失敗する事故は、確率として普通に起きます。
そして片方だけ無効な状態は、設定画面をいくら眺めても見つかりません。「キーが入っている」ことと「入っているキーが正しい」ことは別だからです。管理画面のスクリーンショットを見せてもらっても、キーの値そのものは伏せられていたり途中で切れていたりして、突合できないことがほとんどです。
なぜ気づけないのか――v3の無効キーはエラーを出さない
reCAPTCHA v3の厄介なところは、サイトキーが無効でも見た目には何のエラーも出ないことです。
- reCAPTCHA本体のスクリプト(api.js)は正常に読み込まれる(HTTPステータスは200)
- ブラウザのコンソールにエラーは表示されない
- v3は送信直前にトークンを取る実装が多く、その場合は平時にバッジも出ない
つまり、目視でも通信ログでもコンソールでも検知できません。エラーが表に現れるのは、送信ボタンが押されてトークン取得処理が実行された瞬間だけです。このとき実装によって、症状が2つに分かれます。
- 送信ボタンが無反応になる――トークン取得時のエラーが処理されず、送信処理が途中で止まるケース
- 普通に送信できてしまう――エラー時は検証をスキップする設計になっていて、フォームは動くがスパム防御だけがゼロになっているケース
1は「フォームが壊れた」とすぐ気づけますが、2は誰も気づきません。フォームは届いているので、スパムが増えて初めて「あれ、reCAPTCHA入れたはずでは」となります。「壊れてはいないが、防御だけが効いていない」という状態が静かに続く――これがreCAPTCHA設定ミスのいちばん怖いところです。
実例:「設定は正しい」のに動かなかったケース
実際にあった、住宅向けサービス業の会社サイトでのケースです。問い合わせフォームにreCAPTCHA v3を設置したところ、動作しない。確認を依頼すると「reCAPTCHAのタイプはv3で登録済み、ドメインも合っている」という回答で、管理画面のスクリーンショット上も申告どおり正しい設定でした。
それでも動かない。そこで設定画面を見るのをやめて、実際のページ上でトークン取得処理を直接実行したところ、「Invalid site key」――サイトキーの値そのものが無効、というエラーが返ってきました。実際のドメイン上での実行なので、ドメイン不一致ではありません。管理画面の設定は正しく、しかしサイトに入っているキーがその管理画面のキーと別物だった、ということです。
次に、シークレットキーが有効かどうかを切り分けました。ここで使えるのが、Googleの検証エンドポイント(siteverify)への直接照会です。ダミーのトークンを付けてシークレットキーを送ると、返ってくるエラーコードで判別できます。
invalid-input-secretが返る → シークレットキーが偽物invalid-input-responseだけが返る → トークンが偽物なだけで、シークレットキーは本物
このケースでは後者でした。つまり「シークレットキーは有効、サイトキーだけが無効」。ペアの片方だけが無効なら、原因はほぼコピペミスに絞られます。 キーの再発行を依頼するのか、正しい値を再送してもらうのか、次にやることが一意に決まりました。ここまでの切り分けに掛かった時間は15分程度です。
切り分け手順――3ステップで原因を特定する
上の実例でやったことを、手順として整理します。
ステップ1:ページに出力されているサイトキーと、管理画面のキーを突合する。 ページのソースを表示して「sitekey」や「recaptcha」で検索すると、サイトに実際に入っているサイトキーの文字列が見つかります。これをGoogleのreCAPTCHA管理画面に表示されるサイトキーと1文字ずつ照合します。ここが一致していなければ、その時点で原因確定です。
ステップ2:siteverifyに直接照会して、シークレットキーの生死を確かめる。 ターミナルが使えるなら1行で済みます。
curl -d "secret=シークレットキー&response=dummy" https://www.google.com/recaptcha/api/siteverify
invalid-input-secret が含まれていればシークレットキーが無効、invalid-input-response だけならシークレットキーは有効です。ページに出力されない側のキーを、推測ではなく実測で判定できます。
ステップ3:実際のドメイン上でトークン取得を実行してみる。 ブラウザの開発者ツールのコンソールで grecaptcha.execute() を実行すると、サイトキーが無効な場合はその場でエラーメッセージが返ります。実ドメイン上での実行結果なので、「キーの値の問題」か「ドメイン登録の問題」かもここで切り分けられます。
この3ステップの共通点は、設定画面を見直すのではなく、Googleが返す応答を直接見ることです。「設定は正しいはず」という申告と「実際に動いている」ことの間には、常にズレの余地があります。判定はGoogleのAPIの応答でやるのが確実です。
設置するときに組み込んでおく保険――起こりうる事故と防ぎ方
切り分けと同じくらい大事なのが、設置時点で事故に備えた作りにしておくことです。reCAPTCHAは外部サービスなので、キーの不備以外にも、Google側の応答遅延や仕様変更でトークンが取れなくなる可能性が常にあります。そのときフォームがどう振る舞うかは、実装の設計で決まります。
リスク1:エラー処理の書き方によっては、送信ボタンが完全に沈黙する。 トークン取得のエラーには、非同期のエラーと、実行した瞬間に発生する同期エラーの2種類があります。Promiseの .catch() は前者しか拾いません。無効キーのエラーは同期側で発生するため、.catch() だけ書いてあっても捕まらず、送信処理が止まったまま何も起きない状態になります。try/catchで同期エラーも囲んでおくのが正しい実装です。
リスク2:外部サービス待ちでフォームが道連れになる。 reCAPTCHAの応答がいつまでも返らないケースに備えて、数秒のタイムアウトを設けて、時間切れならreCAPTCHAを諦めて送信する設計にしておきます。外部サービスに何が起きても、フォーム自体は動き続けるようにするためです。
リスク3:検証を厳しくしすぎて、問い合わせが1件も届かなくなる。 サーバー側で「トークンが空なら弾く」と実装すると、reCAPTCHA側に問題が起きた瞬間、すべての問い合わせが止まります。ここは技術ではなく事業の判断です。「スパムが数通届く損害」と「本物の問い合わせが1件も届かない損害」のどちらが大きいか。 問い合わせが売上に直結する店舗ビジネスやサービス業なら、ほとんどの場合は後者の損害が大きい。トークンが空のときは通し、Googleが明確にbotと判定したときだけ弾く、という緩めの設計が実務的な正解になります。
リスク4:スクリプトの置き場所によっては、そもそも実行されない。 WordPressのテーマファイルの末尾にスクリプトを直書きすると、HTMLの閉じタグの外に出力されてブラウザが実行しない、という事故が起こりえます。PHPの構文チェックも通り、HTMLの出力も一見正常なので気づきにくいポイントです。スクリプトは必ず所定のフック(wp_footerなど)経由で出力します。
そして設置が終わったら、必ず自分でテスト送信をして、実際にメールが届くところまで確認します。 さらにサーバー側のログやsiteverifyの応答で、スコアが返ってきていること(検証が実際に機能していること)まで見れば万全です。前述のとおり、「フォームは動くが防御はゼロ」という状態は、テスト送信だけでは見抜けないからです。
まとめ:疑う順番を間違えないためのチェックリスト
reCAPTCHA設置後にフォームの様子がおかしいときは、次の順で確認してください。
- ページソースのサイトキーと管理画面のサイトキーは一致しているか(目で突合)
- siteverifyへの直接照会で、シークレットキーは有効か
- 実ドメイン上でトークン取得を実行して、エラーが返らないか
- エラー時・タイムアウト時にフォームがどう振る舞う実装になっているか
- テスト送信でメールが届き、サーバー側で検証スコアが記録されているか
「設定は正しい」という確認と「動いている」という確認は、別物です。設定画面を何往復するよりも、Googleの応答を1回直接見るほうが速く、確実に原因へたどり着けます。キーは2つで1組、片方だけ無効になりうる――これを頭に入れておくだけで、reCAPTCHAまわりのトラブルの切り分けは大きく短縮できます。