フォームに reCAPTCHA を導入してボットからのアクセスを遮断する


a-blog cms Ver.2.8.0から拡張機能より、GoogleのreCAPTCHA機能が使用できます。 ウェブサイトにアクセスを試みるボットを遮断するために設置されているreCAPTCHAですが一度はどこかで体験したことがあると思います。webのフォームは一番攻撃されやすい箇所になります。reCAPTHAを導入して、ロボットによるスパム投稿を防ぎましょう。


ロボットでないことを証明する

ロボットでないことを証明する


下準備

まずreCAPTCHAを導入するために、reCAPTCHA にアクセスして、必要な情報を取得します。

「Domains」の項目はご利用のサイトのドメインを指定してください。


(スクリーンショット)

サイトのドメイン登録


(スクリーンショット)

Site key と Secret key の取得


サイトを登録し、以下2つのキーを使用しますのでメモしておいてください。

  • Site key
  • Secret key

クライアント実装

下準備ができましたので、まずはクライアントサイドを実装します。

JavaScript

以下コードを ご利用のテーマのフォームの head要素内に読み込んでください。

例えば、simple2016テーマなら themes/simple2016/contact/index.html です。

<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<script>
  function validateRecaptcha ( code ) {
    if ( !!code ) {
      var form = document.querySelector(".recaptcha");
      form.removeAttribute('disabled');
    }
  }
</script>

HTML

次に送信フォームを少し修正します。simple2016テーマなら themes/simple2016/contact/form/main.html を開きます。

以下コードを送信フォーム内に挿入します。ここで、{Site key} は 下準備で取得した Site keyに置き換えてください。

<div class="g-recaptcha" data-callback="validateRecaptcha" data-sitekey="{Site key}"></div>

次に、送信ボタンに recaptcha クラスをふり、 disabled にしておきます。

<input type="submit" name="ACMS_POST_Form_Submit" value="送信する" id="btnSubmit" class="recaptcha btn-attention-block-large" disabled />

完成例

例として themes/simple2016/contact/form/main.html を編集しています。

<!-- BEGIN step#confirm -->
...

<form action="thanks.html" method="post" class="form-btn form-btn-send" enctype="multipart/form-data">

    <div class="g-recaptcha" data-callback="validateRecaptcha" data-sitekey="xxxxxxxxxxxxxxxxxxxxxx"></div>

    <input type="hidden" name="To[]" value="{email}" />
    <input type="hidden" name="AdminReply-To[]" value="{email}" />
    <input type="hidden" name="AdminFrom[]" value="{email}" />
    <input type="hidden" name="step" value="result" />
    <input type="hidden" name="takeover" value="{takeover}" />
    <input type="hidden" name="id" value="contactForm" />
    <input type="submit" name="ACMS_POST_Form_Submit" value="送信する" id="btnSubmit" class="recaptcha btn-attention-block-large" disabled />
</form>

クライアントサイドは完成です。実際に動かしてみましょう。フォームの確認画面まで行くと、reCAPTCHAが表示され、送信ボタンが押せないようになっているかと思います。reCAPTCHAで承認が通ると送信ボタンが押せるようになります。


(スクリーンショット)

チェックするまで送信ボタンが押せない


サーバーサイド実装

クライアントサイドの実装ができると、一見動いていそうに見えますが、このままだと送信ボタンの disabled を開発者ツールなどで削除してしまえば、送信できるようになってしまいます。そこで、サーバーサイドで認証を行いましょう。

認証の仕組み

ユーザーがreCAPTCHAの認証を通ると、ランダムな文字列のコードが生成され、フォーム送信時に一緒に送信されます。 このコードを使って、サーバーサイドでreCAPTCHAのapiにリクエストを投げ、正しいコードかチェックを行うことにより、正常な手段でフォームが送信されたことを確認することができます。

実装

実装にはHook機能を使います。php/ACMS/User/Hook.phpbeforePostFire に以下のコードを追加しましょう。

config.server.phpのHOOK_ENABLEを 1 にしておきましょう。

public function beforePostFire($thisModule)
{
    $moduleName = get_class($thisModule);

    if ( $moduleName === 'ACMS_POST_Form_Submit' ) {
        $secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx';
        $response = $thisModule->Post->get('g-recaptcha-response');
        $api = "https://www.google.com/recaptcha/api/siteverify?secret=${secret}&response=${response}";

        $valid = false;
        if ( $res = @file_get_contents($api) ) {
            $check = json_decode($res);
            if ( $check->success === true ) {
                $valid = true;
            }
        }

        if ( !$valid ) {
            $Field  = $thisModule->extract('field');
            $Field->setMethod('g-recaptcha-response', 'check', false);
            $thisModule->Post->set('step', 'forbidden');
        }
    }
}

ここで、 $secret を、下準備で用意した Secret key で置き換えます。これで実装は完了です。

確認

では実際に、サーバーサイドで認証ができているかチェックしてみましょう。フォームで確認画面まで移動して、 disabled になっている送信ボタンを、開発者ツールで disabled を外して送信してみましょう。以下の画像のようにサーバーサイドで不正なアクセスとして処理されていることが確認できます。


不正なアクセスとして処理される

不正なアクセスとして処理される