reCAPTCHA v3を最低限の実装で簡単に導入する方法

はじめに

サイト制作には欠かせないお問い合わせフォーム。しかしただ設置しただけだと迷惑メールやスパムがどうしても防止できない。そんな時とても役に立つアイテムがgoogleが提供する「reCAPTCHA」。

reCAPTCHA」は簡単に言うと、フォーム送信時にユーザー(送信者)の挙動を監視して、それが人間かロボット(スパムなど)かを判定してくれるサービスです。

今回は、v3バージョンの導入方法についてまとめてみようと思います。

導入方法については検索するとたくさん出てきますが、記事によってアプローチの仕方が若干異なる。もちろんやっている事は全部同じですが、一番簡単な方法を探していてたどり着いたのが公式(笑)。今回は公式のマニュアルを元にできるだけ最低限の実装で導入する方法をまとめてみます。ほぼ公式の解説になってます。

全体の流れ

公式には以下の3ステップで実装する方法が書かれています。

1. 本体のJavaScriptを読み込む
2. フォーム送信関数を設置
3. 送信ボタンに属性を挿入

この3ステップは、フロントエンド側の実装のみで、実際にはバックエンド(サーバ)側にも実装が必要です。なので、以下のステップも追加します。

4. reCAPTCHAから結果を受け取る
5. 判定する

以上5ステップで簡単に実装できます。

事前準備

実装に入る前にまず「reCAPTCHA」に登録します。

登録方法の詳細は省略しますが、サイト登録時の設定内容は以下のような感じです。

recaptcha

「ドメイン」のところへは、設置するサーバのドメインを入れます。複数追加することができますが、セキュリティー上、本番のサーバとローカルの開発環境を一緒に登録してはいけない事になってます。サイト登録は複数できるので、別々に登録しましょう。

ちなみにローカルのドメインとして登録する場合は、「localhost」や「127.0.0.1」となります。開発環境によって別のドメインになる場合もあるので、自分の環境にあったドメインを追加しましょう。

登録が完了すると、「サイトキー」と「シークレットキー」の2つがもらえます。この2つのキーを使用して実装していきます。

フロントエンド側の実装

1. 本体のJavaScriptを読み込む

以下のコードをHTML内に追加します。このスクリプトがほぼほぼすべての処理を自動でやってくれます。

<script src="https://www.google.com/recaptcha/api.js"></script>

2. フォーム送信関数を設置

こちらもHTML内に追加するかJavaScriptファイルに追加します。送信ボタンを押したらフォームを送信するというだけの簡単なコードです。

<script>
   function onSubmit(token) {
     document.getElementById("demo-form").submit();
   }
 </script>

“demo-form”には送信したいフォームのIDを入れます。フォームは各自作成してください。

3. 送信ボタンに属性を挿入

送信ボタンのタグ内に以下のような属性を追加します。

<button class="g-recaptcha"
        data-sitekey="reCAPTCHA_site_key"
        data-callback='onSubmit'
        data-action='submit'>Submit</button>

※ “reCAPTCHA_site_key”のところは先程取得したサイトキーを入れます。

フロントエンド側の実装は以上です。これだけで、フォーム送信時にサイトキーやトークンと共に判定材料となるデータがreCAPTCHAへ送信されます。あとは判定結果を受け取るだけ。

サンプルコード

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SAMPLE FORM</title>
</head>

<body>

    <form id="demo-form" name="myForm" action="./confirm.php" method="POST">
        <input type="text" name="name">
        <input type="text" name="email">
        <button class="g-recaptcha"
            data-sitekey="reCAPTCHA_site_key"
            data-callback='onSubmit'
            data-action='submit'>Submit</button>
    </form>

    <script src="https://www.google.com/recaptcha/api.js"></script>
    <script>
        function onSubmit(token) {
            document.getElementById("demo-form").submit();
        }
    </script>

</body>

</html>

バックエンド側の実装

続いてバックエンド側ですが、こちらは公式にはサンプルスクリプトがないので自分なりに最低限のコードを書いてみました。今回はPHPの場合です。フォームをPOSTされたPHPファイル内に実装します。

4. reCAPTCHAから結果を受け取る

なんと以下の一行で受け取ることができます!

$recap_response = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret=[reCAPTCHA_secret_key]&response=' . $_POST['g-recaptcha-response']);

※ [reCAPTCHA_secret_key]のところは先程取得したシークレットキーを入れます。[]カッコ自体は不要です。

「$recap_response」は任意の変数名です。ここに以下のようなJSON形式で返って来るので、次の「5. 判定する」で判定します。

 {
    "success": true|false,       // 合格か不合格か
    "challenge_ts": timestamp,   // 判定時刻 (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
    "hostname": string,          // ホスト名
    "score": 0~1,                // 判定スコア
    "error-codes": [...]         // エラーがあったらここに入ってくる
}

解説

解説が不要の方は飛ばしてください。

file_get_contents()関数は、任意のURLへアクセスした結果を受け取れます。この場合、以下のreCAPTCHAのAPIからレスポンスを受け取っています。

【判定結果を受け取るAPI】
https://www.google.com/recaptcha/api/siteverify?ここにパラメーター

このAPIには以下の2つのパラメーターが必須です。(付けられるパラメーターはもう1つありますが今回は使いません)

・secret=(シークレットキー)
・response=(トークン)

トークンは、送信ボタンを押した時に自動的に取得され、フォームデータに追加されて送信されています。$_POST['g-recaptcha-response']という変数で取り出すことができます。

5. 判定する

受け取った判定結果を元に以下のようなコードで判定します。

// JSON形式をPHPオブジェクトにデコード
$recap_response = json_decode($recap_response);

// successプロパティ(trueかfalseか)で判定
if ($recap_response->success == false) {
    // 不合格の場合の処理
}

今回はsuccessプロパティで判定していますが、scoreプロパティを使って自分で判定してもよいです。successプロパティはscoreが0.5以上でtrueとなります。

まとめ

今回は最低限の実装ということでしたが、フォーム送信時に別の処理を入れたい場合など、もっと柔軟にコードを書くこともできます。公式でも今回のものとは別にもう一つサンプルとして方法が紹介されています。機会があったらそちらの方も記事にしたいと思います。

追記

ローカル環境でfile_get_contents()関数を使用した時に、タイムアウトが発生する場合は、以下の記事を参考にしてください。

ローカル環境でfile_get_contentsがタイムアウト