タイトル: reCAPTCHA
SEOタイトル: Google reCAPTCHA 完全ガイド (v2/v3)
この本文には実行可能なタグ等が含まれるため、安全のため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>reCAPTCHA</strong> は Google のボット対策サービス。フォーム送信時に人間かどうかを判定</li><li>v2 はチェックボックス / 不可視タイプ、<strong>v3 はスコア型</strong> (0.0 〜 1.0) でユーザー操作不要</li><li>フロント: <code>https://www.google.com/recaptcha/api.js</code> 読込 + Site Key</li><li>バックエンド: <code>POST https://www.google.com/recaptcha/api/siteverify</code> で Secret Key と一緒に検証</li><li>代替: <strong>hCaptcha</strong> / <strong>Cloudflare Turnstile</strong> がプライバシー / 無料枠で人気</li></ul></td></tr></table>
<h2>reCAPTCHA とは</h2>
<p><strong>Google reCAPTCHA</strong> は、Web フォームに対する<strong>自動化されたボット攻撃</strong>を防ぐためのサービスです。ユーザー登録・ログイン・コメント投稿などのフォームに組み込むことで、人間と機械を区別します。Google が無料で提供しており (一定リクエスト数まで)、世界で最も普及した CAPTCHA サービスです。</p>
<h2>バージョンと特徴</h2>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>バージョン</th><th>ユーザー体験</th><th>仕組み</th><th>用途</th></tr></thead>
<tbody>
<tr><td><strong>reCAPTCHA v2 Checkbox</strong></td><td>「私はロボットではありません」にチェック</td><td>マウス操作・Cookie・行動分析</td><td>定番。怪しい場合は画像チャレンジ追加</td></tr>
<tr><td><strong>reCAPTCHA v2 Invisible</strong></td><td>ユーザー操作なし</td><td>ボタンクリック時に裏で判定</td><td>UX を損ねたくないフォーム</td></tr>
<tr><td><strong>reCAPTCHA v3</strong></td><td>完全に透明</td><td>スコア (0.0〜1.0) を返す</td><td>★ 推奨。ページ全体での挙動を分析</td></tr>
<tr><td><strong>reCAPTCHA Enterprise</strong></td><td>v3 + α</td><td>不正検知 API・有償</td><td>大規模・金融系</td></tr>
</tbody>
</table>
<h2>キーの取得</h2>
<ol>
<li><a href="https://www.google.com/recaptcha/admin">https://www.google.com/recaptcha/admin</a> にアクセス (要 Google アカウント)</li>
<li>「+」ボタンで新サイトを登録</li>
<li>reCAPTCHA タイプを選択 (v2 / v3)</li>
<li>ドメインを登録 (<code>example.com</code> のように)</li>
<li><strong>Site Key</strong> (公開) と <strong>Secret Key</strong> (秘匿) が発行される</li>
</ol>
<h2>reCAPTCHA v2 (チェックボックス) の実装</h2>
<h3>フロントエンド</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>お問い合わせ</title>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<body>
<form method="POST" action="/contact">
<input type="text" name="name" placeholder="名前">
<textarea name="message"></textarea>
<!-- ★ ここに reCAPTCHA ウィジェットが表示される -->
<div class="g-recaptcha" data-sitekey="6Lc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"></div>
<button type="submit">送信</button>
</form>
</body>
</html></code></pre>
<h3>バックエンド (PHP)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php"><?php
// フォーム送信時の検証
$token = $_POST['g-recaptcha-response'] ?? '';
if (empty($token)) {
die('reCAPTCHA トークンが見つかりません');
}
$secret = getenv('RECAPTCHA_SECRET_KEY');
$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);
if (!$result['success']) {
error_log('reCAPTCHA failed: ' . json_encode($result['error-codes'] ?? []));
die('CAPTCHA 検証に失敗しました');
}
// 成功: フォーム処理続行
processContactForm($_POST);</code></pre>
<h2>reCAPTCHA v3 (スコア型) の実装</h2>
<p>v3 はユーザーに何も見えませんが、ページ操作から<strong>0.0〜1.0 のスコア</strong>が返ります (1.0 が人間らしい、0.0 がボットらしい)。0.5 を閾値にすることが多いです。</p>
<h3>フロントエンド</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://www.google.com/recaptcha/api.js?render=6Lc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"></script>
</head>
<body>
<form id="contactForm" method="POST" action="/contact">
<input type="text" name="name">
<textarea name="message"></textarea>
<input type="hidden" name="recaptcha_token" id="recaptcha_token">
<button type="submit">送信</button>
</form>
<script>
document.getElementById('contactForm').addEventListener('submit', function(e) {
e.preventDefault();
grecaptcha.ready(function() {
grecaptcha.execute('6Lc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', {action: 'submit_contact'})
.then(function(token) {
document.getElementById('recaptcha_token').value = token;
e.target.submit();
});
});
});
</script>
</body>
</html></code></pre>
<h3>バックエンド (PHP)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">$token = $_POST['recaptcha_token'] ?? '';
$secret = getenv('RECAPTCHA_SECRET_KEY');
$ch = curl_init('https://www.google.com/recaptcha/api/siteverify');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'secret' => $secret,
'response' => $token,
'remoteip' => $_SERVER['REMOTE_ADDR'],
]),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5,
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
// v3 では success + score + action を確認
if (!$result['success']) {
die('CAPTCHA 検証失敗');
}
if ($result['action'] !== 'submit_contact') {
die('アクション不一致');
}
if ($result['score'] < 0.5) {
error_log("Low score: {$result['score']}");
die('ボットの疑い');
}
processContactForm($_POST);</code></pre>
<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
php artisan vendor:publish --provider="Anhskohbo\NoCaptcha\NoCaptchaServiceProvider"</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_SITEKEY=6Lc_xxxxxxxxxxxxx
// NOCAPTCHA_SECRET=xxxxxxxxxxxxxx
// Blade テンプレート
<form method="POST" action="/contact">
@csrf
<input type="text" name="name">
{!! NoCaptcha::renderJs() !!}
{!! NoCaptcha::display() !!}
<button type="submit">送信</button>
</form>
// Controller でバリデーション
$request->validate([
'name' => 'required',
'g-recaptcha-response' => 'required|captcha',
]);</code></pre>
<h2>レスポンスフィールド</h2>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>フィールド</th><th>意味</th><th>v2</th><th>v3</th></tr></thead>
<tbody>
<tr><td>success</td><td>検証成功か</td><td>あり</td><td>あり</td></tr>
<tr><td>score</td><td>0.0 (ボット) 〜 1.0 (人間)</td><td>-</td><td>あり</td></tr>
<tr><td>action</td><td>execute 時のアクション名</td><td>-</td><td>あり</td></tr>
<tr><td>challenge_ts</td><td>判定タイムスタンプ</td><td>あり</td><td>あり</td></tr>
<tr><td>hostname</td><td>判定が行われたドメイン</td><td>あり</td><td>あり</td></tr>
<tr><td>error-codes</td><td>エラー詳細</td><td>あり</td><td>あり</td></tr>
</tbody>
</table>
<h2>代替サービス</h2>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e8f5e9"><th>サービス</th><th>特徴</th><th>無料枠</th></tr></thead>
<tbody>
<tr><td><strong>hCaptcha</strong></td><td>プライバシー重視、Cloudflare 採用</td><td>月 100 万件まで無料</td></tr>
<tr><td><strong>Cloudflare Turnstile</strong></td><td>不可視・無料・無制限</td><td>完全無料</td></tr>
<tr><td><strong>FriendlyCaptcha</strong></td><td>GDPR 準拠、EU 拠点</td><td>有償 (一部無料)</td></tr>
<tr><td><strong>MTCaptcha</strong></td><td>多言語・カスタマイズ豊富</td><td>月 1 万件無料</td></tr>
</tbody>
</table>
<h2>FAQ</h2>
<p><strong>Q: v3 のスコア閾値はいくつにすべき?</strong><br />
A: Google 公式は 0.5 を推奨。最初は記録のみで運用してログを見て調整するのが定石。0.3 未満を即拒否、0.3〜0.7 はメール認証等の追加、0.7+ は通すといった段階運用も。</p>
<p><strong>Q: localhost で開発したい</strong><br />
A: reCAPTCHA 管理画面のドメイン欄に <code>localhost</code> を追加すれば動作します。</p>
<p><strong>Q: 1 ページに複数 reCAPTCHA を置きたい</strong><br />
A: v2 では <code>grecaptcha.render()</code> でウィジェット ID を指定して複数描画可能。v3 では <code>action</code> を変えて execute を複数回呼びます。</p>
<!-- @RESTORED_IMG_v1 -->
<h2>📸 参考画像</h2>
<p style="color:#666;font-size:0.85em;margin-bottom:1em">※ 旧バージョンから引き継いだ参考画像です。手順・図解の補助としてご覧ください。</p>
<p style="text-align:center;margin:1em 0"><img alt="参考画像" src="/uploadImage/20180912094717_1966618.jpg" style="max-width:640px;width:100%;height:auto;border:1px solid #ccc;border-radius:4px" /></p>