お問い合わせフォームにまつわるあれこれ

  • 投稿日:
  • by
  • カテゴリ:

 (この記事は要約するとGoogle reCAPTCHA v3を皆ちゃんと実装しているのかよ!というグチです)

 ひと月ちょっと前に、CS60新神戸を立ち上げるという相談がありました。早い話、ネット予約が出来るようにしたいということで、これについては早々に使えるソリューションを見つけました。

 問い合わせも必要だよねと、「お問い合わせフォーム」を設置するためにいくつか検索してみると、Googleフォームを利用する方法が見つかります。で、試すわけですが、送信者がGmailのアドレスだし回答のコピーを自動送信できるけど、これ求めているものとちょっと違う。さらに検索するとGoogle Apps Scriptと組み合わせると、問い合わせの内容を自動返信できるようになったので、まあこれでよいかなと一段落。と思ったのですが、運用するには不安な要素も。

  • フォームをメンテするときにうっかり操作ミスすると、既存問い合わせ済みのものが再送信される事故
  • フォームをサイトに設置したときに下部に「このコンテンツは Google が作成または承認したものではありません。」などという文言を表示、割り切ればよいことだけど
  • スパム対策はどうするの?Googleフォーム自体で自動送信するときは、画像選択のボット対策があるようだけど、それを無効にしてGoogle Apps Scriptで対抗する場合は無い?

 実際、Googleフォームで運用しているところも見られるので悪くはないと思うのですが、コントロールが難しいのがね。スプレッドシートへ自動転記されていくので記録として残すのに便利なのですけど。

 書込みフリーな「お問い合わせフォーム」というのはスパムメールの温床に繋がるので、スパム対策をどうしようかなと探していると、Google reCAPTCHAを使ったものが見かけられます。「私はロボットではありません」というやつもそれの一バージョンです。

 ベースとなるメールフォームは、フリー素材として配布されているものを流用。それにGoogle reCAPTCHA v2を設定(なぜv2を選んだかは直感)。それを組み込み色々試して使えそうかなと、各種ブラウザでの確認を始めたところ、Chromeだけ何故かうまくいきません。なぜかSubmitするボタンが無効になってしまう。さらにreCAPTCHA v2のチェックボックスではなく、Submitボタンやその近傍をくりっくしてもreCAPTCHA v2が反応する、なぜか画像選択がでまくる。といったことで散々な結果に。Android Chromeだと問題ないのに。

 reCAPTCHA v2を諦め、reCAPTCHA v3を実装に切り換え。この両者何が違うかというと、

  • v2はフォーム内に「私はロボットではありません」のチェックボックスが設置されるのに対し、v3は設置されない。ただブラウザ右下にreCAPTCHAのシールが常に貼られる
  • v2、v3ともにトークンという一定期間有効なデータを生成しサーバーへ送信。サーバー側でGoogleへ問い合わせ有効か否かを確認。異なるのはv3ではスコアという評価値が返ってくること。スコアが低いと怪しいやつという判断に繋がる

 さて、reCAPTCHA v3に切り換わっても、実装はほとんど変わらないと思いきやトークンの生成に落とし穴がありました。

 v2ではチェックボックスをチェックしてから再び要求されるまではトークンが有効なのでトークンの有効期間を意識する必要はないのですが、v3はページを表示してからトークンの管理が始まっていたのです。v3を記事にしてよく見掛けるのはページを表示したとき直後にトークンを取得、もう一つはフォームをSubmitするときにトークンを取得というパターン。

Goolgeのサンプルコードとして、次のコードを実行してねというのがあります。しかしv3の実装には落とし穴が待っていました。

  <script>
grecaptcha
.ready(function() {
grecaptcha
.execute('reCAPTCHA_site_key', {action: 'homepage'}).then(function(token) {
...
});
});
</script>
  • ページロード直後にgrecaptcha.execute()を実行しないと、サーバーチェックで "invalid-input-response" エラー
  • ページロード直後にgrecaptcha.execute()を実行しても、フォーム内にデータを埋め込まないとやはり"invalid-input-response" エラー
  • 定期的にgrecaptcha.execute()実行してトークンを再取得しないと、"timeout-or-duplicate" エラー。定期的というのは2分から3分の間の模様
  • 落とし穴ではないけどSubmit時にgrecaptcha.execute()しても、直近のgrecaptcha.execute()の結果とトークンが変わらなかった。推測するにGoogle reCAPTCHA v3はページを表示してから常に一定毎にトークンを更新する必要(かつページ内の埋め込みデータも更新)があって、更新しないとタイムアウト。頻繁にgrecaptcha.execute()しても一定期間はトークンが変わらないという特性がある模様

この落とし穴を確認するために、スコアが最低になるという状況も起きました。これらを検索してみたのですが日本語ページでは見つけられなくて、海外掲示板でこれに嵌りこんでいるのを見掛けました。日本語記事の多くがWordPressのContact Form 7というプラグインとの組み合わせなので個別運用で悩んでいる方は少ないのかもしれません。

あれこれコードを書いて、結局ページロード直後に実行およびsetIntervalによる定期実行に落ち着きました。

 せっかくなので、Googleフォーム風のチェックも出来るようにしたいと、フォームのページをサンプルから変更しています。jQueryを使うとこんなことが出来るんだねと感心しながらね。

 さてGoogle reCAPTCHA v3のスコア運用ですが、今は 0.5未満 で運用しようと考えています。ときどきスコアが悪くて送信しないという可能性があるのですが、スパムボット対策ということで配慮いただけたらと思います。(CS60新神戸を利用しようとする人でこれを見るのはほとんどいないと思いますが)