Hatoblog(はとブログ)

reCAPTCHAとは?フォームでbotを防げるreCAPTCHA v3の特徴と使い方

「わたしはロボットではありません」でおなじみのreCAPTCHA。一度は使ったことがあるという方も多いと思います。

この記事では、そんなreCAPTCHAの最新版の特徴や使い方を解説していきます。botによるフォームへのスパム攻撃を防ぐためにも、ぜひとも使い方をマスターして、いざという時に利用できるようにしましょう。

それでは始めていきましょう。

目次

reCAPTCHAとは

概要は既に説明しましたが、reCAPTCHAとはGoogleが提供している、Webフォームに設定しbotによる悪質なアクセスを防ぐための仕組みです。

こういう画像でおなじみのやつですね。あとは難解な「信号機が写っている画像を選ぶ」とか、「横断歩道が写っている画像を選ぶ」みたいなのもこれの一部です。

reCAPTCHAは時を重ねる毎にどんどん進化しており、現在はバージョン3(v3)が最新バージョンです。

reCAPTCHA v3とは

reCAPTCHA v3は、なんと遂に「ユーザーが何も操作しなくてもbotかどうか判断できる」ようになりました。上記画像のボタンを押す必要すらありません。

詳しいアルゴリズムは公開されていませんが、これまで続いてきたreCAPTCHAシリーズの正統後継者だけあって、確かな信頼性を持っています。

さらに、このreCAPTCHAはデータを蓄積させることでどんどん精度が増していきます。こうやってユーザーのデータを集め、集合知として利用するのはGoogleの得意分野ですね。

reCAPTCHA v3の使い方

基本的にはGoogleのreCAPTCHAガイドに沿って進めます。手順は以下の通りです。

実際のサイトに設置する部分が少し難しいかもしれませんが、一つ一つやっていけば大丈夫です。

専用サイトからreCAPTCHAのアクセスキーを取得

まずはreCAPTCHA管理コンソールページから、今回reCAPTCHAを設置するサイトを登録します。

自分が判断できるラベル名とサイトのドメイン等を設定します。reCAPTCHAタイプは最新版の「v3」を選択しましょう。

右下を見てもらうと分かりますが、なにげにこのフォーム自体もreCAPTCHAを使っていますね。ちなみに、reCAPTCHAが設定された実際のフォームにも、このように右下にreCAPTCHAマークが付きます。

進むと、下のような画面が出てきます。

このサイトを登録してみました。サイトキーとシークレットキーが表示されるので、コピーしておきましょう。

実際のサイトに設置

reCAPTCHA v3のガイドでは、下記のような実装例となっています。最低限のフレームだけ書かれている感じで、実際に使うには少し不親切な気もします。

<script src="https://www.google.com/recaptcha/api.js?render=_reCAPTCHA_site_key"></script>
<script>
grecaptcha.ready(function() {
    grecaptcha.execute('_reCAPTCHA_site_key_', {action: 'homepage'}).then(function(token) {
       ...
    });
});
</script>

ですので、ここからは実際の運用を想定して、僕が以前作ったコードを見ながら解説していきます。基本的にはこの通りに作れば動くと思います。

大きく分けて「login.php上部のPHP部分」「login.php下部のHTML部分」「login.phpで読み込まれているlogin.jsのJavaScript部分」の3つのブロックに分かれています。

全文を載せてからそれぞれ解説していきます。以下全文です。

<?php
// reCAPCHAから返ってきた後の処理(初回訪問時はスルー)
if( isset( $_POST ) && !empty( $_POST['recaptcha_token'] ) ){
  $recaptcha_token = $_POST["recaptcha_token"];
  $url = "https://www.google.com/recaptcha/api/siteverify?secret={SECRET_KEY}&response=" . $recaptcha_token;
  $response = @file_get_contents($url);
  $response = json_decode( $response, true );

  // BOTかどうかを判断して、それぞれの処理を行う
  if ($response['success'] != true || $response['score'] == 0 ){
    // BOTです!!
  } else {
    // 人間です!!
  }
}
?>
<!doctype html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>ログイン</title>
  <!-- reCAPTCHA -->
  <script src='https://www.google.com/recaptcha/api.js?render={SITE_KEY}'></script>
  <!-- jQuery -->
  <script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
  <script src="login.js"></script>
</head>
<body>

  <form id="myForm" action="" method="post">
    <input type="text" name="id" required>
    <input type="password" name="pw" required>
  </form>
  <div id="myFormSubmit">ログインする</div>

</body>
</html>
const $formElement = $('#myForm'); // フォーム要素
let isSubmiting = false; // 送信処理中かどうか

// 送信ボタンをクリックしたら
$('#myFormSubmit').click(function(){
  
  // 送信処理中でなければ処理を始める
  if( !isSubmiting ){
    isSubmiting = true; // 送信処理中フラグをONに
    
    // フォーム内容のバリデーションはここで行う

    // reCAPTCHAの処理
    grecaptcha.ready(function() {
      try {
        grecaptcha.execute('{SITE_KEY}', {action: 'login'})
        .then(function(token) { // トークン取得成功
          // formのhiddenにtokenを格納
          $formElement.append('<input type="hidden" name="recaptcha_token" value="' + token + '">');
          // 送信
          $formElement.submit();
        }, function(reason) { // トークン取得失敗
          sendError( 'セッション情報の取得に失敗しました。再度操作してください。' );
        });
      } catch(e) {
        sendError( 'エラーが発生しました。再度操作してください。' );
      }
    });

  }
});

以上。
それぞれ解説していきます。

HTML部分

PHP部分は一旦無視してHTML部分から。

<!doctype html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>ログイン</title>
  <!-- reCAPTCHA -->
  <script src='https://www.google.com/recaptcha/api.js?render={SITE_KEY}'></script>
  <!-- jQuery -->
  <script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
  <script src="login.js"></script>
</head>
<body>

  <form id="myForm" action="" method="post">
    <input type="text" name="id" required>
    <input type="password" name="pw" required>
  </form>
  <div id="myFormSubmit">ログインする</div>

</body>
</html>

reCAPTCHAと、(僕はjQueryが書きやすいので)jQueryと、メインロジックになるlogin.jsを読み込みます。reCAPTCHA読み込み部分の{SITE_KEY}には先程のサイトキーを入れてください。

フォームはIDとパスワードの2つで、別途divタグで作った送信ボタンがあります。これは良くないので、みなさんはbuttonタグで作りましょう。HTML部分に関してはこれだけです。

JavaScript部分

const $formElement = $('#myForm'); // フォーム要素
let isSubmiting = false; // 送信処理中かどうか

// 送信ボタンをクリックしたら
$('#myFormSubmit').click(function(){
  
  // 送信処理中でなければ処理を始める
  if( !isSubmiting ){
    isSubmiting = true; // 送信処理中フラグをONに
    
    // フォーム内容のバリデーションはここで行う

    // reCAPTCHAの処理
    grecaptcha.ready(function() {
      try {
        grecaptcha.execute('{SITE_KEY}', {action: 'login'})
        .then(function(token) { // トークン取得成功
          // formのhiddenにtokenを格納
          $formElement.append('<input type="hidden" name="recaptcha_token" value="' + token + '">');
          // 送信
          $formElement.submit();
        }, function(reason) { // トークン取得失敗
          sendError( 'セッション情報の取得に失敗しました。再度操作してください。' );
        });
      } catch(e) {
        sendError( 'エラーが発生しました。再度操作してください。' );
      }
    });

  }
});

送信ボタンをクリックしたら、click()メソッドが動きます。多重送信を防ぐ処理とバリデーションを行いますが、今回の趣旨からは逸れるので割愛します。

「reCAPTCHAの処理」部分でトークンを生成し、フォームの内容に含めて送信します。つまりフォームの送信データはID、パスワード、reCAPTCHAトークンの3つとなります。

$formElement.submit();の部分でフォームを送信しています。formタグのaction属性は空白になっているため、自分自身(login.php)が送信先になります。送信後、先程スルーしたPHP部分が動くという仕組みです。

また、こちらにも{SITE_KEY}がありますので、同じようにサイトキーを入れてください。

PHP部分

<?php
// reCAPCHAから返ってきた後の処理(初回訪問時はスルー)
if( isset( $_POST ) && !empty( $_POST['recaptcha_token'] ) ){
  $recaptcha_token = $_POST["recaptcha_token"];
  $url = "https://www.google.com/recaptcha/api/siteverify?secret={SECRET_KEY}&response=" . $recaptcha_token;
  $response = @file_get_contents($url);
  $response = json_decode( $response, true );

  // BOTかどうかを判断して、それぞれの処理を行う
  if ($response['success'] != true || $response['score'] == 0 ){
    // BOTです!!
  } else {
    // 人間です!!
  }
}
?>

送信完了後、送信先として読み込まれたときには、$_POSTに値が入ってきているのでifの中に入ります。{SECRET_KEY}がありますので、同じ要領でシークレットキーを入れてください。

中では受け取ったreCAPCHAトークンを判定用のURLへ飛ばし、スコアを取得しています。このスコアは0.0に近いほどbotで、1.0に近いほど人間という判定です。このコードでは0以外は人間として扱っていますが、状況に応じて適宜変更してください。

BOTです!!、人間です!!の部分が最終的な処理になります。BOTであれば強制ログアウト、人間であればログイン後のトップページにジャンプさせるなど、それぞれの処理を行ってください。

以上で一連の流れが完了します。

まとめ

実際に運用しているものを簡素化させたものを紹介しました。reCAPCHAは初心者から見ると難しく見えるかもしれませんが、少しWebに慣れてくると割とシンプルに思えてくると思います。

botを使ったフォーム自動送信プログラムは、メール爆撃ほどではないですが存在します。Googleがこういうツールを開発しているのもあり、スパムや脆弱性を突いた悪質なプログラムを防ぐ重要性は高いです。

特にレンタルサーバーなどでは他のサイトにも迷惑がかかることもあるので、フォーム関連のセキュリティについてはしっかりと勉強するようにしましょう。そういう意味でもreCAPCHAは手軽に導入できて便利です。是非覚えて利用していきましょう。