タイトル: エラー一覧
SEOタイトル: reCAPTCHA エラー一覧と対処完全ガイド
この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li><strong>missing-input-secret</strong>: シークレットキー未送信 → サーバ側で secret パラメータ漏れ</li><li><strong>invalid-input-secret</strong>: シークレットキー誤り → v2/v3 の取り違え、サイトキーを使っていないか</li><li><strong>missing-input-response</strong>: トークン未送信 → フォームに <code>g-recaptcha-response</code> が無い</li><li><strong>invalid-input-response</strong>: トークン無効 → 期限切れ (2 分)、別ドメインで生成、テストキー本番混在</li><li><strong>timeout-or-duplicate</strong>: 同一トークン二重送信 / 期限切れ → 検証は 1 回のみ・即時に実施</li></ul></td></tr></table>
<h2>reCAPTCHA とは</h2>
<p>Google が提供する Bot 判定サービス。フォームの自動投稿(スパム / 不正登録)を防ぐためにクライアント側で <code>g-recaptcha-response</code> トークンを生成し、サーバ側で Google の API に問い合わせて検証します。</p>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>バージョン</th><th>特徴</th><th>UI</th></tr></thead>
<tbody>
<tr><td>v2 Checkbox</td><td>「私はロボットではありません」</td><td>クリック + 画像チャレンジ</td></tr>
<tr><td>v2 Invisible</td><td>透明、ボタンクリックで起動</td><td>必要時のみチャレンジ</td></tr>
<tr><td>v3</td><td>スコア (0.0〜1.0) 返却、UI なし</td><td>無し、サイト側で閾値判定</td></tr>
<tr><td>Enterprise</td><td>有料、高度な機能</td><td>v3 ベース</td></tr>
</tbody>
</table>
<h2>error-codes の主要パターン</h2>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#ffebee"><th>エラーコード</th><th>意味</th><th>主な原因</th></tr></thead>
<tbody>
<tr><td><code>missing-input-secret</code></td><td>secret パラメータが無い</td><td>サーバ送信パラメータ漏れ</td></tr>
<tr><td><code>invalid-input-secret</code></td><td>secret が無効</td><td>キー打ち間違い、サイトキー渡しミス、v2/v3 取り違え</td></tr>
<tr><td><code>missing-input-response</code></td><td>response パラメータが無い</td><td>クライアントからのトークン送信漏れ</td></tr>
<tr><td><code>invalid-input-response</code></td><td>response が無効</td><td>期限切れ (2 分)、改竄、別サイトキーで生成</td></tr>
<tr><td><code>bad-request</code></td><td>リクエスト不正</td><td>HTTP メソッド誤り、ヘッダー不足</td></tr>
<tr><td><code>timeout-or-duplicate</code></td><td>期限切れ or 二重利用</td><td>トークン使い回し、検証遅延</td></tr>
<tr><td><code>browser-error</code></td><td>ブラウザ側エラー</td><td>JS 無効、CSP ブロック</td></tr>
</tbody>
</table>
<h2>サーバ側検証の最小実装 (PHP)</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-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 の疑いがあります');
}</code></pre>
<h2>各エラーの詳細対処</h2>
<h3>missing-input-secret / invalid-input-secret</h3>
<ul>
<li>Google Cloud Console → reCAPTCHA admin で<strong>シークレットキー</strong> (6L で始まる) を再確認</li>
<li>サイトキー (HTML 側、6L から始まる) と<strong>取り違えていないか</strong></li>
<li>v2 用キーで v3 を検証していないか(バージョン違いキーは互換性無し)</li>
<li><code>.env</code> に <code>RECAPTCHA_SECRET</code> が定義されているか、<code>php artisan config:cache</code> 漏れ</li>
<li>テスト用キー(<code>6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe</code> 等)を本番に残していないか</li>
</ul>
<h3>missing-input-response</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!-- ✅ v2 Checkbox -->
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<form method="POST" action="/submit">
<div class="g-recaptcha" data-sitekey="YOUR_SITE_KEY"></div>
<!-- ↑ submit 時に hidden の name="g-recaptcha-response" が自動生成される -->
<button type="submit">送信</button>
</form>
<!-- ✅ v3 (透明) -->
<script src="https://www.google.com/recaptcha/api.js?render=YOUR_SITE_KEY"></script>
<script>
grecaptcha.ready(() => {
grecaptcha.execute('YOUR_SITE_KEY', { action: 'login' }).then((token) => {
document.getElementById('recaptcha-token').value = token;
});
});
</script>
<form id="login-form">
<input type="hidden" name="g-recaptcha-response" id="recaptcha-token">
</form></code></pre>
<h3>invalid-input-response</h3>
<ul>
<li>トークンの寿命は<strong>2 分</strong>。フォーム表示から送信まで時間がかかる場合は<strong>再生成</strong>が必要</li>
<li>SPA / 多段ページのフローでトークンを使い回している</li>
<li>サイトキーとシークレットキーが<strong>別ドメイン分</strong>になっている(ステージング用キーを本番で使用など)</li>
<li>Google Cloud で<strong>ドメイン登録</strong>済か(v2/v3 とも本番ドメインを admin に追加要)</li>
</ul>
<h3>timeout-or-duplicate</h3>
<ul>
<li>同一トークンを<strong>2 回検証</strong>している(リダイレクト後再送、リトライ機構)</li>
<li>サーバ側のキューに積んで遅延処理 → 既に 2 分経過</li>
<li>クライアント側 JS バグでトークンを使い回し</li>
</ul>
<h2>Laravel での実装 (anhskohbo/no-captcha)</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-bash">composer require anhskohbo/no-captcha</code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// .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') !!}
<form method="POST">
@csrf
{!! NoCaptcha::display() !!}
<button>送信</button>
</form>
// バリデーション
$request->validate([
'g-recaptcha-response' => 'required|captcha',
]);</code></pre>
<h2>v3 のスコア活用</h2>
<p>v3 は 0.0 (Bot 確実) 〜 1.0 (人間確実) のスコアを返します。閾値はサイト次第:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">$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);
}</code></pre>
<h2>その他のトラブル</h2>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#fff3e0"><th>症状</th><th>原因</th><th>対処</th></tr></thead>
<tbody>
<tr><td>reCAPTCHA が表示されない</td><td>サイトキー間違い、CSP がドメインブロック</td><td>キー確認 / <code>Content-Security-Policy</code> に google.com 追加</td></tr>
<tr><td>localhost で動かない</td><td>許可ドメイン未登録</td><td>admin で <code>localhost</code> を追加 or テストキー使用</td></tr>
<tr><td>毎回画像チャレンジが出る</td><td>IP / ブラウザがスコア低</td><td>v3 移行 / Enterprise 検討</td></tr>
<tr><td>iframe 内で動かない</td><td>X-Frame-Options ブロック</td><td>埋め込み元の許可設定</td></tr>
</tbody>
</table>
<h2>FAQ</h2>
<p><strong>Q: v2 と v3 を同じページで併用できる?</strong><br />
A: 技術的には可能ですが、JS の競合が起きやすいので非推奨。サイト全体を v3 に統一が無難です。</p>
<p><strong>Q: ローカル開発でテストするには?</strong><br />
A: Google 公式の<strong>テスト用キー</strong>(<code>6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI</code> など)を使うと常に成功します。本番リリース時は必ず本物のキーに差し替え。</p>
<p><strong>Q: 検証 API へのリクエストがタイムアウトする</strong><br />
A: 本番サーバから <code>https://www.google.com</code> へ OUT 通信が許可されているか確認。プロキシ越しの場合は <code>HTTPS_PROXY</code> 設定。</p>