GoogleにはreCAPTCHAと呼ばれる、外部向けのフォーム等に於いてボットなどによるスパムを防止する為の仕組みが用意されています。通常のHTMLのフォームに組み込んで利用する事ができる大変便利なものですが、Google Formにはこのような機能が搭載されていません。

内部で使う分には必要のない機能ですが、どうしてもお問い合わせフォームにボットが悪さをしてゴミメールを沢山送ってくるのは困ります。そこで今回、お手製のスパム防止用のreCAPTCHA的仕組みをつけて見ました

難易度:

今回使用するファイル

今回は2つのファイルを利用します。GoogleスライドはプレゼンではなくreCAPTCHA的画像生成の為の土台として使います。フォームには画像生成、フォームのパーツ入れ替えの大きく2つの機能を持たせてあります。

事前準備と仕組み

事前準備

セットアップする箇所は4箇所。

  1. スパム防止用フォームを開くと上にパズルのアイコンが出るので、セットアップを実行
  2. 初期化を実行すると、このフォームのIDがスクリプトプロパティに格納されます。
  3. トリガー設置で、画像生成とフォームパーツの入れ替え用関数がスクリプトトリガーに1時間毎でセットされます。
  4. スパム防止用フォームのスクリプトエディタを開く
  5. slides.gsにあるfileidは画像生成用スライドのファイルIDを入れます。
  6. slides.gsにあるfolderidは画像を生成するフォルダのIDを入れます。

これで利用可能になります。フォームのreCAPTCHAパーツと「上記画像の文字を入力してください」は変更してはいけません。

仕組み

Google Apps Scriptにはテキストを画像化するような素敵なメソッドは用意されていません。また、SlidesAppにも直接スライドを画像化するようなメソッドは用意されていません。

そこで今回は

  1. UrlfetchAppにてスライドをPDFならぬPNG形式に変換する仕組みを使って画像を生成
  2. スライドなので色々カスタマイズが可能
  3. Formの回答の検証では、スクリプトで生成し画像と同じ文字が入っていないと送信できないようにしてあります。
  4. 今回はランダムな文字列で作っていますが、例えば計算式を画像で生成し、答えをValidation側にセットしておくことで、文字入力ではなく計算結果でreCAPTCHAが作れます。
  5. フォントを色々変更してみるのもスパム対策になるでしょう。
  6. 本来のGoogle reCAPTCHAはCloud ConsoleでAPIを有効にし、キーを取得してJavaScriptでHTMLにコードを記述する面倒な手法ですが、こちらの手法はFormだけでなく通常のHTMLでも利用可能です。WordPressに魔改造で貼り付けたものにも、組み込む事はおそらく可能です。

図:テキスト画像に表示されてるものと一致しないと送信できない

ソースコード

今回はgetPropsetPropについてはそのままスクリプトプロパティの値の出し入れの為に直接関数を用意しています。slides.gsが画像生成用のスクリプト、makeForm.gsがフォームのパーツ差し替え用スクリプトになります。

slides.gs

  • 今回はSlidesAppというスライド操作用のクラスを利用します。
  • 1枚しか入っていないスライドに文字のテキストボックスのみです。この文字を変更し、UrlfetchAppにて画像(PNG形式)へ変換します。変換するコードはPDFを変換するコードと非常に似ています。
  • Spreadsheetとは異なり、getTextしてからsetTextをするという奇妙な方法でテキストボックスの値の書き換えをします。
  • 書き換えする文字は半角英数字でgenerateCaptcha関数で行っています。正規表現でValidationを行うので記号などは入れてはいけません。
  • changepict関数でスライドを画像化し、指定のフォルダに格納しています。
  • changepict関数に続けて、changeForm関数を実行し、フォームのパーツを入れ替えています。
  • スクリプトプロパティには画像のID, 生成時間, captchaで生成したワードを入れています。
  • このslide2jpg関数Triggerにて毎日1時間毎に実行し、画像を生成&入れ替えを自動で行わせることになります。

makeForm.gs

  • Formには画像パーツreCAPTCHAの文字を入力するテキストボックスを用意してあります。
  • FormのImageを取得し、reCAPTCHAと名前のついているものだけを対象としています。生成済みの画像をBlobで取得してsetImageで差し替え、300pxに縮小しています。
  • Validationでは回答の検証をコードで入れてありますTextValidationBuilderクラスを使って作るのですが、このクラス通常のテキストの「含む」というものが生成するメソッドがありません。今回はrequireTextMatchesPatternを利用して、正規表現で一致するものという条件をセットしています。
  • ValidationにはreCAPTCHAで生成したワードを検証用ワードとしてセットしています。
  • setValidationでセットし、必ずsetRequiredをtrueにします(そうしないとスパム対策の意味がない)
  • changeFormを手動実行すると、フォームのパーツが最新の画像とreCAPTCHAの文字による検証に入れ替わります。実際にはこれをTriggerで自動で行わせています。
  • あまりTriggerで短い間隔でセットすると、1日のTrigger実行とUrlfetchAppのQuotaに引っかかってしまうので、ほどほどに。

図:reCAPTCHAらしい画像と入力欄の出来上がり

関連リンク

共有してみる: