エンジニ屋.com(エンジニヤドットコム)

分かりやすくを意識して情報発信!

【汎用的】reCAPTCHA v3の導入方法【Eccube4】


本記事は、Eccube4のフォームにreCAPTCHA v3を導入する方法紹介します。

紹介で導入する箇所はEccube4の会員登録とクレジット登録(GMO決済プラグイン)ですが、他ページのフォームでも導入可能な様に汎用的なソースコードで実装していきます。

reCAPTCHAとは

Webフォームなどに登録する際やログイン時に、botなどによる悪質なアクセスからWebサイトを守るためのGoogleから提供されている機能です。
2018年10月29日にGoogleからreCAPTCHAの新バージョンreCAPTCHA v3が正式公開されました。
reCAPTCHAのAIが、ユーザーのページ内での行動をスコアとして算出し、botかそうでないかを判別します。
さらに、reCAPTCHA v3を配置したページでのユーザーの動きを学習し、利用が増えるとともに行動スコアの精度が高まっていくこともv3の特徴です。

参考:https://www.synergy-marketing.co.jp/blog/using_recaptcha_on_form

reCAPTCHAについて、詳しく知りたい方はこちらの記事を参考にされるととても分かりやすいです。

「reCAPTCHA」って?スパム対策に効果的なreCAPTCHAをフォームに入れてみた | BLOG | シナジーマーケティング株式会社

全体的なフロー

実装方法の全体的な流れを最初に説明しておきます。

  1. GooglerereCAPTCHAの登録(Googleアカウントが必要です。)

  2. app\Customize\Util\RecaptchaUtil.phpにベースとなる設定キーを記述する

  3. app\template\default\Block\recaptcha.twigにフォームを生成するブロックを作成

  4. app\template\default\Entry\index.twigで3で作成したブロックの呼び出し (会員登録に適用)

  5. app\Customize\Controller\EntryController.phpでコントローラでフォームから送信された値を確認

  6. app\Plugin\GmoPaymentGateway4\Resource\template\mypage_card.twig 4と同じ(クレジット登録に適用)

  7. app\Plugin\GmoPaymentGateway4\Controller\MypageCardController.php 5と同じ

reCAPTCHAの登録

既にお持ちのGoogleアカウントを使用するなら問題ありませんが、 先ずはGoogleアカウントが必要です。

アカウント取得済みであれば下記公式サイトからreCAPTCHAの登録を行います。

Google reCAPTCHA公式サイト
https://www.google.com/recaptcha/admin/create

アクセスすると下記イメージ画像のような画面に遷移します。

reCAPTCHA登録

ラベルは自由に設定して大丈夫です。
ドメインには利用するドメイン名を入力してください。

入力が完了したら送信ボタンを押します。

送信後にサイトキーとシークレットキーを取得できるので、こちらをサイトのソースに設定していきます。

定数としてキーをセット

汎用的に利用したいので、ベースとなる設定キーを1つのファイルに記述します。

app\Customize\Util\RecaptchaUtil.phpでディレクトリとファイルを作成します。

<?php

namespace Customize\Util;

class RecaptchaUtil {
    private static $secret = '<シークレットキー>';
    private static $contentStr = 'https://www.google.com/recaptcha/api/siteverify?secret=%s&response=%s';
    public const SITE_KEY = '<サイトキー>';
    public const INPUT_NAME = 'recaptchaResponse';
    private const MIN_SCORE = 0.5;

    private function __construct() { }

    public static function check($response){
        $url = sprintf(self::$contentStr, self::$secret, $response);
        $recaptcha = json_decode(file_get_contents($url));
        $result = $recaptcha->success && ( property_exists($recaptcha, 'score') && $recaptcha->score >= self::MIN_SCORE );
    
    return (bool)$result;
    }
}

解説

phpファイルにclassを作成します。

クラス名は何でも良いですがここではRecaptchaUtilとします。

定数でシークレットキー、reCAPTCHAのAPIのURL、サイトキー、スコアラインを記述します。 シークレットキー、サイトキーはreCAPTCHAで取得したキーを記述してください。

スコアについて簡単に説明すると、reCAPTCHAから返却されるスコアが0に近いほど、botの可能性かあるので0.5にしています。(デフォルトでも0.5が設定されているようですが、念の為設定しています。)

checkメソッドを作成します。

引数をresponseをセットして、 sprintfで定数で定義しているcontentStrでurlにsecretキーとresponse値をセットしてURLを作成します。

file_get_content関数でwebページのHtml情報を取得してます。

取得する情報はjson形式なので、jsondecodeでurlの内容をphpオブジェクトで変数に格納しています。

返却された情報のseccessにはtrue且つスコア が設定したスコアよりも上回っているかを確認します。

上回っていたらtrue、下回っていたらfalseを返します。

次にフォーム送信時にreCaptchaへ検証用にサイトキーとトークンを送信する処理を記述します。

フォームの呼び出し

app\template\default\Block\recaptcha.twig

{% set site_key = constant('Customize\\Util\\RecaptchaUtil::SITE_KEY') %}
{% set inputName = constant('Customize\\Util\\RecaptchaUtil::INPUT_NAME') %}

<script src="https://www.google.com/recaptcha/api.js?render={{ site_key }}"></script>
<script>
grecaptcha.ready(function() {
    var form = $('{{ form }}');
    var recaptchaInput = $("<input>").attr({type: 'hidden', name: '{{ inputName }}'});

    form.append(recaptchaInput);

    form.on('submit', function(e){
        grecaptcha.execute('{{ site_key }}', {action: 'homepage'}).then(function(token) {
            recaptchaInput.val(token);
            form[0].submit();
        });
        return false;
    })
});
</script>

解説

汎用的に使用できるようにブロックで作成します。

set sitekeyとset inPutName はtwig内で変数を格納する方法です。

先程Utilファイルで定義した定数を呼び出してます。

https://www.google.com/recaptcha/api.js...でライブラリを読み込んでいます。

その下でgrecapth.ready(function){...を使用してページを開いた時にトークンを発行して、 送信した時にトークンと一緒にデータを送信して、トークンで検証の為に通信しています。

var form = $('{{ form }}');の{{ form }}とは元のフォームを受け取ります。
後ほど値を渡す処理を書きます。

ブロックを呼び出し

まずは会員登録のページにブロックを呼び出しを記述していきたいと思います。
元の記述を若干変更する必要があります。

app\template\default\Entry\index.twig

元の記述

 <form method="post" action="{{ url('entry') }}" novalidate class="h-adr">

変更後の記述

 <form id="entryForm"  method="post" action="{{ url('entry') }}" novalidate class="h-adr">

form全体の値を後ほど受け取る処理を記述するためにidを付与します。

追加の記述

  <input type="hidden" name="mode" value="confirm" />

元はsubmitボタン押した際にmodeの値が送信されますが、その処理除外してしまうのでhiddenとして値が飛ぶように記述します。

    {% include "Block/recaptcha.twig" with {'form': '#entryForm'} %}
{% endblock %}

先程作成したブロックを呼び出します。 withでformという変数でid entryFormの値をブロックに渡しています。 これがブロック内で記述した$('{{ form }}');の箇所です。

フォーム送信後の処理

app\Customize\Controller\EntryController.php

 if ($form->isSubmitted() && $form->isValid()) {
    switch ($request->get('mode')) {
       case 'confirm':
          log_info('会員登録確認開始');

         //Recaptchaチェック
         if( false === RecaptchaUtil::check($request->get(RecaptchaUtil::INPUT_NAME)) ){
              $this->addError( 'recaptcha_error');
         return $this->redirectToRoute('entry');

解説

//Recaptchaチェックよりも前は元からあるソースです。

case 'confirm':の下にUtilファイルで作成したcheckメソッドを呼び出します。引数にはトークンを渡します。

もし返却された値がfalseの場合、エラーが表示され会員登録の画面へ戻ります。

以上で会員登録ページにreCAPTCHAが導入出来ました。

汎用性を紹介する為に同じようにクレジット登録ページにも導入します。(GMO決済プラグインインストールしている場合)

ブロックを呼び出し

app\Plugin\GmoPaymentGateway4\Resource\template\mypage_card.twig

</div>
{% include "Block/recaptcha.twig" with {'form': '#form1'} %}
{% endblock %}

解説

作成したBlockを呼び出します。

フォーム送信後の処理

app\Plugin\GmoPaymentGateway4\Controller\MypageCardController.php

 if ($form->isSubmitted() && $form->isValid()) {

   //Recaptchaチェック
   if( false === RecaptchaUtil::check($request->get(RecaptchaUtil::INPUT_NAME)) ){
      $this->addError(trans('front.common.recaptcha_error'));
      return $this->redirectToRoute('gmo_mypage_card_edit');
   }

解説

//Recaptchaチェックよりも前は元からあるソースです。

フォームが送信されたあとにcheckメソッドを呼び出します。

あとは会員登録と同様の処理です。

以上でクレジット登録にも導入完了しました。

汎用的なソースなので少し変更を加えるだけで必要な箇所に複数reCAPTCHAの導入が可能です。

お疲れ様でした!