2024-06-09

古い掲示板に reCAPTCHA V3 を実装した。

当サイトの復旧が完了したものの、閲覧者の方々が気軽に足跡残しが出来る掲示板がないのはちょっと寂しいなと思い、以前使用していた掲示板「picobbs」を設置しようと思いましたが、随分昔とは違いスパムボットの様な機械による自動送信型の迷惑行為に悩まされ掲示板を閉鎖する方も多い様で、スパム対策がなされてない古い掲示板システム(最早過去の遺物?)は格好の餌食なので、昔からよく見かける画像認証の様な機能でも実装してみようかと考えました。ただ、画像認証も数字やアルファベットの様な単純な仕組みだと簡単に突破される恐れもあり、対策を施すのであればもっと確りとした良い方法でなければなりません。

スパムボットは海外からが多いらしく、日本語を入力する仕組みだとそもそも入力出来ずに突破され難い様で、日本人なら誰でも直ぐに分かる様な質問をフォームの最後にでも添えておき、回答を入力させる単純な方法でも良さそうですが、Googleが無償(有償有り)で提供しているreCAPTCHAがあるので、利用しない手はないと考え実装してみる事にしました。

余談になりますが、画像認証は、歪んだり擦れたりなどして機械に読み取り難くした文字を画像で表示し、それを利用者(人間)が目視でその文字を入力する方法ですが、アクセシビリティーの観点として問題ないのでしょうか?私は視覚障碍者ではありませんが、画像認証は度々入力を失敗した経験があります(老眼かw)。同じ様に、reCAPTHA v2 もその点で欠点を抱えていると思います。ウェブ制作者でこの辺を語っている情報は皆無ですよね?(視覚障害者とCAPTCHA)v3だと完全自動型のシステムなので、利用者に入力などの手間も無く便利で良いと思います。決して、Googleの回し者ではありませんよ(笑)

reCAPTCHAについてネット検索をしてみると、記載された例文が複雑で初心者には実装が難しく思える情報の散見が多くみられます。今回は基本的な事に抑えて記載します。プログラムに詳しくない方でも実装はそう難しくはないと思います。

reCAPTCHA V3 とは

reCAPTCHA v3 を使用すると、ユーザーの操作を必要とせずに、ウェブサイト上の不正なトラフィックを検出できます。reCAPTCHA v3 では、CAPTCHA チャレンジを表示する代わりにスコアを返すため、ウェブサイトに最適なアクションを選択できます。

[引用: reCAPTCHA v3 の概要 より]

reCAPTCHA V3 の実装

reCAPTCHAの実装方法は実に簡単です。

  1. Googleアカウントをお持ちでなれば、Google アカウントの作成が必要です。
  2. お持ちのアカウントで、reCAPTCHAを使用(実装)する為の登録をします。
  3. reCAPTCHAを実装するページに実装する為に必要となるソースコード(後述)を追加します。
  4. 送信された内容の処理(入力フォームのPOST処理)の前に、reCAPTCHAによる鑑定でスパムボットであれば弾く処理を施します。

たったこれだけでスパムを防御することが可能です。勿論、悪意ある人間による荒らし行為までは防ぐ事は出来ませんが(そこは必要に応じてIPアドレスを表示するなどの方法で対処可能かと)、機械か人間かを判別する仕組みとしては現時点で最も安心できる簡単な方法だと思います。

注釈

reCAPTCHAの登録時にはちょっと注意が必要で、デフォルトでは Enterprise API (有償版:実際には規定回数までは無償利用可能)なので、無償で利用したい場合には、登録時に Switch to create a legacy key に切り替えて登録を行う必要があります。

登録したら、reCAPTCHA v3 のガイドを参考にしながら、実装したいページに下記コードを追加します。

JavaScript API
<script src="https://www.google.com/recaptcha/api.js"></script>
トークンを処理するコールバック関数
 <script>
   function onSubmit(token) {
     document.getElementById("demo-form").submit();
   }
 </script>
例文の demo-form 値は、実装するフォーム(form要素のid属性値)に対応します。適切な値に変更して下さい。例えば、form要素のid属性値がpost_formならば、その値(post_form)に変更しなければなりません。
HTMLのsubmit(送信)ボタン
<button class="g-recaptcha" 
        data-sitekey="reCAPTCHA_site_key" 
        data-callback='onSubmit' 
        data-action='submit'>Submit</button>

2つのscript要素の挿入箇所はhead要素内でもbody要素内でも大丈夫です。上記3つを追加して実装されたページを表示すると、右下にreCAPTCHAバッジが表示されます。表示されれば実装は成功です。然しながら、これだけでは人間か機械(bot)かの判定を行うだけで判定結果を得るだけでは何の役にも立ちません。ですから、reCAPTCHAによる判定結果を使い、コードに手を加える必要があります。つまり、利用者が送信ボタンを押して送信された内容を処理する為のコード記述箇所にreCAPTCHAによる判定結果によりスパムを弾く(ブロックする)処理を施せば良い訳です。

PHPでの処理

以下は、送信ボタンが押された時に処理される関数内の冒頭に付け加えた内容(関連する記述のみ抜粋)です。今回私がreCAPTCHAを実装した掲示板「picobbs」をご存知の方であれば、「picobbsはPerl言語で書かれている筈だが??」と言語の違いを疑問に思われる事でしょう。実は、私自信でpicobbsをPerlからPHPに移植して手を加えています。当初はオリジナルのPerlコードに手を加えて実装を試しましたが、実行テスト中にサーバのモジュール不足に気付き、この為だけにサーバ管理者のホッシーさんにモジュール対応をリクエストするのは心苦しく感じ、個人的にPHPの方が使用頻度が高く使い勝手が良いので、この際だしとリハビリがてらPHPに移植してみました(苦笑)。2日で完成しました。ログファイルは完全互換で動作します。オリジナルにあったバグ(否や仕様)なども序に修正しました。見た目は完全にpicobbsです。(*´σー`)エヘヘw

※「picobbs」は、今から20年以上前にMakoto氏により無償配布されていた簡易掲示板システムで、W3C仕様に準拠した綺麗なHTMLソースコードを吐く掲示板としてウェブ制作者の間で知られカスタマイズも容易でしたが、配布サイトは残念な事に疾うの昔に消滅しています。一応、Wayback Machineにアーカイブされています(picoBBS)が、picobbsに限らず古いシステムは現在使用するにはそのままでは使用に耐えるものではありません。

話しが脱線しましたが、reCAPTCHAによる防御機能を発動する為に、以下の様な感じで送信内容を処理する記述に手を加えます。以下のPHPでの記述例は、投稿フォーム送信時に呼び出されるdo_post関数の中に記述しています。

function do_post() {
  ...
  $user_token = filter_input(INPUT_POST, "g-recaptcha-response");
  if ($user_token === null) { // 念の為
    // エラー処理
  }
  $params = [
    'secret' => /* RECAPTCHA V3 シークレットキー */,
    'response' => $user_token
  ];
  $options = [
    'http' => [
      'method' => 'POST',
      'header' => 'Content-Type: application/x-www-form-urlencoded',
      'content' => http_build_query($params)
    ]
  ];
  // APIリクエスト
  $filename = 'https://www.google.com/recaptcha/api/siteverify';
  $context = stream_context_create($options);
  $response = json_decode(file_get_contents($filename, false, $context));
  // bot認定された場合の処理
  // successがtrueでも、指定score値(以下では0.5)を下回る場合にスパムとして扱うので注意が必要。
  if ($response->success === false || $response->score <blockcode 0.5) {
    $error = $response->{'error-codes'};
    // botならばエラー処理して終了
  }
  // 上記if文に一致しなければ、可として通常通りの処理を以下に続ける…
  ...
}

上記の /* RECAPTCHA V3 シークレットキー */ の箇所には、reCAPTCHAの登録完了時に発行されたシークレットキーの文字列が入ります(登録後は v3 Addmin Console の設定から確認できます)。エラー処理は必要に応じて。判定のscore値(スコアの解釈)は、1.0は安全で0.0はボットの可能性が非常に高い。人間と機械のしきい値が0.5なので、上記方法では0.5を基準に判定しています。但し、利用者の環境によっては数値が増減し、数値を厳しく設定すると人間でも弾かれる可能性がある訳なのでご注意ください。

ざっとですが、以上です。組み込むのがPHPであれば、私の例が殆どそのまま使用出来るので初心者でも簡単だと思います。

reCAPTCHA バッジを非表示にする。

よくある質問に記載されています。バッジを非表示にすることもできますが、指定されたテキストを表示する必要があります。

This site is protected by reCAPTCHA and the Google
<a href="https://policies.google.com/privacy">Privacy Policy</a> and
<a href="https://policies.google.com/terms">Terms of Service</a> apply.

CSSで表示位置などをカスタマイズしたい場合には、クラスセレクタで属性値.grecaptcha-badgeを使い設定すれば良いです。

今後の予定

余談ですが、「reCAPTCHA」の情報を検索をすると、Google公式の解説よりも数多くの解説がヒットします。近年は、昔よりもマークアップの構造化、セマンティクスが重要視される様になった事は良い事ですが、自分が求めている情報が上位だから必ず合致する訳でもないと思います。SEO対策について語る情報資源も多いですが、検索ワードによっては嘘や誤情報であれSEO対策されたリソースが上位ヒットします。その昔、meta keywordsの埋め込みで上位ヒットを狙ったやり方と何ら変わってないと思います。試しに、「福岡弁」と検索してみて下さい。全て誤情報ばかりがヒットします。上位ヒットに限らずです。本当に正しい情報は、今では数少なくなった福岡弁話者である私のブログ(福岡弁 ~あなたの知らない福岡弁~)ぐらいしか存在しませんが、上位どころか全くヒットしません。完全に埋もれています。ですから、最近流行りのAIチャットも嘘の情報を吐きます。これは差別です。人権侵害です。「訴えてやる!」by ダチョウ倶楽部(笑)そういう訳で、今後の更新予定はAIに正しい知識を吐かせる為にも「福岡弁」についてのコンテンツを充実させていきたいと考えてます。サイト復旧した目的はそれが最大の理由だったりして・・・。