タイトル: エラー一覧
SEOタイトル: reCAPTCHA エラー一覧と対処完全ガイド
| この記事の要点 |
|
reCAPTCHA とは
Google が提供する Bot 判定サービス。フォームの自動投稿(スパム / 不正登録)を防ぐためにクライアント側で g-recaptcha-response トークンを生成し、サーバ側で Google の API に問い合わせて検証します。
| バージョン | 特徴 | UI |
|---|---|---|
| v2 Checkbox | 「私はロボットではありません」 | クリック + 画像チャレンジ |
| v2 Invisible | 透明、ボタンクリックで起動 | 必要時のみチャレンジ |
| v3 | スコア (0.0〜1.0) 返却、UI なし | 無し、サイト側で閾値判定 |
| Enterprise | 有料、高度な機能 | v3 ベース |
error-codes の主要パターン
| エラーコード | 意味 | 主な原因 |
|---|---|---|
missing-input-secret | secret パラメータが無い | サーバ送信パラメータ漏れ |
invalid-input-secret | secret が無効 | キー打ち間違い、サイトキー渡しミス、v2/v3 取り違え |
missing-input-response | response パラメータが無い | クライアントからのトークン送信漏れ |
invalid-input-response | response が無効 | 期限切れ (2 分)、改竄、別サイトキーで生成 |
bad-request | リクエスト不正 | HTTP メソッド誤り、ヘッダー不足 |
timeout-or-duplicate | 期限切れ or 二重利用 | トークン使い回し、検証遅延 |
browser-error | ブラウザ側エラー | JS 無効、CSP ブロック |
サーバ側検証の最小実装 (PHP)
$token = $_POST['g-recaptcha-response'] ?? '';
$secret = env('RECAPTCHA_SECRET');
$response = file_get_contents(
'https://www.google.com/recaptcha/api/siteverify?' . http_build_query([
'secret' => $secret,
'response' => $token,
'remoteip' => $_SERVER['REMOTE_ADDR'],
])
);
$result = json_decode($response, true);
/*
[
'success' => true,
'challenge_ts' => '2026-06-10T01:23:45Z',
'hostname' => 'example.com',
'score' => 0.9, // v3 のみ
'action' => 'login', // v3 のみ
'error-codes' => [...], // エラー時のみ
]
*/
if (!($result['success'] ?? false)) {
$codes = $result['error-codes'] ?? [];
throw new Exception('reCAPTCHA 失敗: ' . implode(',', $codes));
}
// v3 はスコア閾値判定
if (($result['score'] ?? 0) < 0.5) {
throw new Exception('Bot の疑いがあります');
}
各エラーの詳細対処
missing-input-secret / invalid-input-secret
- Google Cloud Console → reCAPTCHA admin でシークレットキー (6L で始まる) を再確認
- サイトキー (HTML 側、6L から始まる) と取り違えていないか
- v2 用キーで v3 を検証していないか(バージョン違いキーは互換性無し)
.envにRECAPTCHA_SECRETが定義されているか、php artisan config:cache漏れ- テスト用キー(
6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe等)を本番に残していないか
missing-input-response
invalid-input-response
- トークンの寿命は2 分。フォーム表示から送信まで時間がかかる場合は再生成が必要
- SPA / 多段ページのフローでトークンを使い回している
- サイトキーとシークレットキーが別ドメイン分になっている(ステージング用キーを本番で使用など)
- Google Cloud でドメイン登録済か(v2/v3 とも本番ドメインを admin に追加要)
timeout-or-duplicate
- 同一トークンを2 回検証している(リダイレクト後再送、リトライ機構)
- サーバ側のキューに積んで遅延処理 → 既に 2 分経過
- クライアント側 JS バグでトークンを使い回し
Laravel での実装 (anhskohbo/no-captcha)
composer require anhskohbo/no-captcha// .env
NOCAPTCHA_SECRET=6LXXXXXXX_secret_key
NOCAPTCHA_SITEKEY=6LXXXXXXX_site_key
// config/no-captcha.php
return [
'secret' => env('NOCAPTCHA_SECRET'),
'sitekey' => env('NOCAPTCHA_SITEKEY'),
'options' => [
'timeout' => 30,
],
];
// Blade
{!! NoCaptcha::renderJs('ja') !!}
// バリデーション
$request->validate([
'g-recaptcha-response' => 'required|captcha',
]);
v3 のスコア活用
v3 は 0.0 (Bot 確実) 〜 1.0 (人間確実) のスコアを返します。閾値はサイト次第:
$score = $result['score'] ?? 0;
$action = $result['action'] ?? '';
if ($action !== 'login') {
abort(400, 'action mismatch');
}
if ($score >= 0.7) {
// 通常処理
} elseif ($score >= 0.3) {
// 追加チャレンジ(メール認証 / SMS)
} else {
// ブロック or 詳細ログ
Log::warning('Low reCAPTCHA score', ['score' => $score, 'ip' => request()->ip()]);
abort(403);
}
その他のトラブル
| 症状 | 原因 | 対処 |
|---|---|---|
| reCAPTCHA が表示されない | サイトキー間違い、CSP がドメインブロック | キー確認 / Content-Security-Policy に google.com 追加 |
| localhost で動かない | 許可ドメイン未登録 | admin で localhost を追加 or テストキー使用 |
| 毎回画像チャレンジが出る | IP / ブラウザがスコア低 | v3 移行 / Enterprise 検討 |
| iframe 内で動かない | X-Frame-Options ブロック | 埋め込み元の許可設定 |
FAQ
Q: v2 と v3 を同じページで併用できる?
A: 技術的には可能ですが、JS の競合が起きやすいので非推奨。サイト全体を v3 に統一が無難です。
Q: ローカル開発でテストするには?
A: Google 公式のテスト用キー(6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI など)を使うと常に成功します。本番リリース時は必ず本物のキーに差し替え。
Q: 検証 API へのリクエストがタイムアウトする
A: 本番サーバから https://www.google.com へ OUT 通信が許可されているか確認。プロキシ越しの場合は HTTPS_PROXY 設定。