この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:13
ページ更新者:atom
更新日時:2026-10-07 10:15:41

タイトル: v2の使い方
SEOタイトル: reCAPTCHA v2の使い方(サンプル付き)

この記事の要点
  • reCAPTCHA v2 の導入方法(チェックボックス UI 版)
  • 前提: Google アカウントでログイン
  • 手順: 公式の My reCAPTCHA でサイト登録 → ラベル / v2 / ドメインを設定 → サイトキーとシークレットキー取得
  • 実装: フロントに data-sitekey 付きの div を置き、サーバで g-recaptcha-response を検証

 

本稿はreCAPTCHA v2の導入方法に関して説明します。

 

前提

Googleアカウントを所有していて、ログインしている。

 

サイト情報の登録

以下の画像は2018年の登録画面です。画像と当時の選択手順を残していますが、現在の管理画面は異なります。2026年10月時点のキー管理・移行はGoogle Cloudの移行案内を確認してください。既存のv2キーとSiteVerifyによる連携は継続できますが、この記事はEnterpriseのcreateAssessment実装例ではありません。

旧公式ページにアクセスして「My reCAPTCHA」を選択します。

v2の使い方

 

続いて、ラベル(適当な名前)を入力、「reCAPTCHA v2」を選択、「Send alerts to owners」を選択します。

「reCAPTCHA v2」を選択すると更にreCAPTCHAを導入するドメインの登録と利用規約の同意を促されます。

「Send alerts to owners」にチェックを入れることで何らかの異常があった場合メールが送信されます。

v2の使い方

サイトにreCAPTCHAを導入

登録が完了したら導入先のサイトの<head>タグに以下のコードを実装します。

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

 

以下はチェックボックス型v2の実装例です。サイトキーはHTMLへ置き、シークレットキーはサーバー側の環境変数へ設定します。両者を取り違えず、秘密鍵をHTML・公開リポジトリ・ログへ出さないでください。PHP例はPHP 8系とcurl拡張を前提にしています。

reCAPTCHAの導入箇所である<form>タグ内に以下のコードを実装します。

※「data-sitekey」はご自分のSite Keyを入力してください。

form.html: 検証・期限切れ・エラーのコールバック

<form action="verify.php" method="post">
  <!-- アプリ側のCSRFトークンは既存の仕組みで追加してください。 -->
  <div class="g-recaptcha"
       data-sitekey="YOUR_SITE_KEY"
       data-callback="enableBtn"
       data-expired-callback="disableBtn"
       data-error-callback="captchaError"></div>
  <button id="comment-submit" name="comment_btn" type="submit" disabled>送信</button>
  <p id="captcha-message" role="status"></p>
</form>
<script>
function enableBtn(token) {
  document.getElementById('comment-submit').disabled = !token;
  document.getElementById('captcha-message').textContent = token ? '' : 'チェックしてください。';
}
function disableBtn() {
  document.getElementById('comment-submit').disabled = true;
  document.getElementById('captcha-message').textContent = '期限が切れました。再度チェックしてください。';
}
function captchaError() {
  document.getElementById('comment-submit').disabled = true;
  document.getElementById('captcha-message').textContent = '通信できません。接続を確認して再試行してください。';
}
</script>
<!-- コールバックの定義後に読み込む。このタグはページ内に1回だけ。 -->
<script src="https://www.google.com/recaptcha/api.js" async defer></script>

検証コールバックにトークンが渡されたら送信ボタンを有効にします。有効期限切れ・通信エラーでは再び無効にします。単にチェックボックスを押したことではなく、コールバックの結果で判断します。上の単独api.js例と下の完全例を両方貼らず、読み込みは1回にしてください。

form.htmlはverify.phpへPOSTします。YOUR_SITE_KEYを自分のサイトキーへ置き換え、実際のフォームでは既存のCSRF対策・入力欄を組み合わせてください。ボタン無効化は操作補助であり、送信リクエストは改変できるため、サーバー検証を省略できません。

 

以下、サーバーサイドの実装例です。(PHP)

同じディレクトリへrecaptcha.php、recaptcha-http.php、verify.phpの3ファイルを配置します。RECAPTCHA_SECRETに秘密鍵、RECAPTCHA_HOSTNAMEに許可するホスト名(example.comのようにスキーム・パスなし)をサーバー環境変数として設定してください。値が空なら成功扱いにしません。取得方法はサーバー管理方法に合わせ、公開ファイルへ秘密鍵を記載しないでください。

recaptcha.php: 応答を判定する関数

<?php

function verifyRecaptcha(mixed $token, string $secret, string $hostname, callable $send): bool
{
    if (!is_string($token) || trim($token) === '' || $secret === '' || $hostname === '') {
        return false;
    }
    try {
        $reply = $send(['secret' => $secret, 'response' => $token]);
        if (!is_array($reply) || ($reply['status'] ?? 0) !== 200 || !is_string($reply['body'] ?? null)) {
            return false;
        }
        $data = json_decode($reply['body'], true, 512, JSON_THROW_ON_ERROR);
        return is_array($data)
            && ($data['success'] ?? false) === true
            && (!array_key_exists('error-codes', $data) || $data['error-codes'] === [])
            && !array_key_exists('score', $data)
            && ($data['hostname'] ?? null) === $hostname;
    } catch (Throwable $e) {
        // 通信・JSONの失敗を検証成功として扱わない。
        return false;
    }
}

recaptcha-http.php: SiteVerifyへPOSTする関数

<?php

function recaptchaHttpPost(array $fields): array
{
    if (!function_exists('curl_init')) {
        throw new RuntimeException('PHP cURL extension is required');
    }
    $curl = curl_init('https://www.google.com/recaptcha/api/siteverify');
    if ($curl === false || !curl_setopt_array($curl, [
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => http_build_query($fields, '', '&', PHP_QUERY_RFC3986),
        CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CONNECTTIMEOUT => 3,
        CURLOPT_TIMEOUT => 8,
    ])) {
        throw new RuntimeException('Verification request setup failed');
    }
    $body = curl_exec($curl);
    if ($body === false) {
        throw new RuntimeException('Verification request failed');
    }
    return ['status' => curl_getinfo($curl, CURLINFO_HTTP_CODE), 'body' => $body];
}

verify.php: フォームの受信処理

<?php

require __DIR__ . '/recaptcha.php';
require __DIR__ . '/recaptcha-http.php';

if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
    http_response_code(405);
    header('Allow: POST');
    exit;
}
$token = $_POST['g-recaptcha-response'] ?? null;
$secret = getenv('RECAPTCHA_SECRET') ?: '';
$hostname = getenv('RECAPTCHA_HOSTNAME') ?: '';

if (!verifyRecaptcha($token, $secret, $hostname, 'recaptchaHttpPost')) {
    http_response_code(400);
    exit('検証できませんでした。再度チェックしてください。');
}

// ここで初めて本来の送信処理へ進む。CSRF・入力検証・権限検査は別途必要。
echo '検証成功';

 

サーバー検証で確認すること

  • g-recaptcha-responseが未送信・空・配列なら検証を失敗にします。文字列トークンだけを送ります。
  • SiteVerifyへsecretとresponseをPOSTし、HTTP失敗・タイムアウト・JSON解析失敗を成功にしません。TLS証明書検証は無効化しません。
  • successが真のbooleanであり、hostnameが設定したホストと一致し、error-codesがある場合は空配列であることを確認します。この例はチェックボックス型v2専用なので、score付きの応答も拒否します。v3へ流用しないでください。
  • トークンは2分以内・1回限りです。再送時や期限切れは再検証を促し、古いトークンを使い回しません。
  • 成功後に初めてフォームの業務処理へ進みます。CAPTCHAはCSRF対策・入力検証・認可・送信回数制限の代わりではありません。

この例は1ホストのみ許可します。複数ホストが必要なら管理した許可リストと照合し、リクエスト由来のHost値をそのまま期待値にしないでください。失敗理由は必要に応じて秘密鍵・生トークンを含めずサーバー側へ記録し、利用者には一般的な再試行案内を返します。

利用上限も監視する

Googleの移行案内では、SiteVerifyが上限超過時にsuccess=trueとscore=0.9、エラーメッセージを返す場合があると説明しています。成功フラグだけを見て許可しないでください。上の関数は非空のerror-codesとscore付き応答を拒否しますが、これだけで製品の上限管理やすべての応答形式を保証するものではありません。管理画面の利用状況・エラーを監視し、必要なら公式のAssessment方式への移行を別途検討します。

導入後の動作確認

  1. 未チェック時は送信ボタンが無効、チェック成功時は有効、期限切れ・エラー時は無効になるか確認します。
  2. 正常な検証後は「検証成功」、未送信・不正トークン・ホスト不一致・通信失敗ではHTTP 400となり業務処理へ進まないか確認します。
  3. GETでverify.phpへアクセスすると405になるか、秘密鍵がページソース・レスポンスに含まれていないか確認します。
  4. 検証用キーと本番キーを分離します。公式テストキーは検証を通すためのものなので、本番で使用しないでください。

この記事の判定関数は外部通信を模した17ケース、画面のコールバックはDOMテストで確認しています。実キーを使ったGoogle側の検証・実サイトへの導入全体は未検証です。

公式資料: v2ウィジェットとコールバック、SiteVerifyの検証仕様、テストキー・利用上限のFAQ(2026年10月確認)。