PHPでの画像認証にSecurimageではなく画像選択方式のreCapchaを使ってみよう

  • 2
    Like
  • 0
    Comment

PHPのWEBアプリケーションの画像認証としてSecurimageを使われている方が多いと思います。
この種の画像認証の課題として以下のようなものが挙げられています。

  • 難読化されすぎていて、人が読めない
  • 画像処理をすればコンピュータ(ロボット)でも突破できる

代替の手法として、パズル形式のCapy Puzzle CAPTCHAや、指定された画像を選択するreCapthaが存在します。
今回は、Googleが提供しているReCaptchaをPHPで利用する方法をまとめました。

すでにPHPでの利用方法をまとめてらっしゃる方がいましたので、そちらを参考にさせていただきました。
参考:GoogleのreCAPTCHAをPHPで使う

reCaptchaのAPIリファレンスによるとPOSTで送るように記載されてましたので、今回はPOSTとして作成しました。
※利用開始にはGoogleアカウントが必要です・

手順は以下の通りです。

  1. reCapthaのページからキーを発行
  2. クライアントのViewにHTMLタグを埋め込む
  3. クライアントからPOSTされたデータをGoogleのAPI経由で検証

reCapthaのページからキーを発行

reCapthaのGet reCAPTCHAボタンからキーの発行画面に移動します。

Label と Domains を入力するとキーが発行されます。

  • Label: 管理用につけるラベルですので分かりやすい名前をつけてください

  • Domains: 複数ドメインに対して同一のキーを割り当てることができます。
    開発環境のドメインが別の場合などは複数行に渡ってドメインを記載してください

※G Suiteを使っている場合は、管理者アカウントでログインしたほうが良いかと思います。
※現時点では、このAPIはGoogle API Consoleでは管理されていないようです。

クライアントのViewにHTMLタグを埋め込む

キーが入力されているHTMLタグも生成されますので、そのままコピペしていただければよいかと。

jsファイルの読み込みタグを追加します。

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

reCaptchaを表示したい箇所に以下のタグを追加します。
XXXXXXXXXXXXX 部分は Site Key で置き換えてください。

<div class="g-recaptcha" data-sitekey="XXXXXXXXXXXXX"></div>

このViewのFormからPOSTすると、g-recaptcha-responseというPOSTパラメータにハッシュ化された文字列が送られてきます。
その値をAPIのパラメータに渡してチェックする流れになります。

クライアントからPOSTされたデータをGoogleのAPI経由で検証

お使いのWEBフレームワークに合わせてPOSTされたデータとクライアントのIPアドレスを取り出します。
※ELBがいる場合はELBのIPアドレスを取り出さないようにお気をつけください。

$recaptha_response = $_POST['g-recaptcha-response'];
$remoteip = $_SERVER['REMOTE_ADDR'];
$check_result = checkReCaptha($recaptha_response, $remoteip); // checkReCapthaというfunctionがある前提で

チェック用の関数は素で書くとこのようになります。

function checkReCaptha($recaptha_response, $remoteip) {
  $url = 'https://www.google.com/recaptcha/api/siteverify';

  $data = http_build_query([
      'secret' => 'XXXXXXXXXXXXX', // Secret Key を指定
      'response' => $recaptha_response,
      'remoteip' => $remoteip,
  ], '', '&');

  $header = implode("\r\n", [
      'Content-Type: application/x-www-form-urlencoded',
      'Content-Length: ' . strlen($data)
  ]);

  $context = [
      'http' => [
          'method' => 'POST',
          'header' => $header,
          'content' => $data,
      ]
  ];

  $json = json_decode(file_get_contents($url, false, stream_context_create($context)), true);
  return $json['success'] === true;
}

APIの応答はJSON形式です。
画像認証に成功した場合は success フイールドに true が入ります。
画像認証に失敗した場合や、キー情報が間違っている場合には error-codes フィールドに配列形式でエラーの理由が返却されます。