#turnstile (2)
概要
reCAPTCHA v3 から Cloudflare Turnstile へ移行する際の実装パターン。Turnstile は無料・プライバシーフレンドリーで CF Pages ネイティブ対応。
キー情報
- テストキー
- サイトキー:
1x00000000000000000000AA - シークレット:
1x0000000000000000000AA
- サイトキー:
- 本番環境: Cloudflare Dashboard で生成
クライアント側(React/Svelte)
// CDN 読み込み(head に挿入)
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
// Explicit rendering(推奨)
turnstile.render('#turnstile-container', {
siteKey: import.meta.env.PUBLIC_TURNSTILE_KEY,
theme: 'light',
callback: (token) => {
// トークン取得後の処理(フォーム送信など)
console.log('Turnstile token:', token);
}
});
// リセット(フォーム送信後)
turnstile.reset();
サーバー側(CF Pages Functions / Node.js)
// POST /api/verify-captcha
const response = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
secret: env.TURNSTILE_SECRET_KEY,
response: token
})
});
const data = await response.json();
if (!data.success) {
throw new Error('Captcha verification failed');
}
メリット
- reCAPTCHA より実装が簡単
- ユーザー側のプライバシー尊重(データ共有なし)
- CF Pages との相性が良い
- 無料で使用可能
背景
- Google reCAPTCHA は Google infrastructure 依存
- Cloudflare Pages への移行に伴い、Cloudflare 内部で完結する Turnstile に変更
差異比較
| 項目 | Google reCAPTCHA | Cloudflare Turnstile |
|---|---|---|
| チャレンジ | ロボット判定 | ロボット判定 |
| パフォーマンス | 速い | より高速(CF エッジで実行) |
| プライバシー | Google に送信 | CF 内部で完結 |
| 料金 | 無料 | 無料(CF Pages Free含む) |
| デプロイ | Google Console | wrangler.toml + env var |
| キャプチャUI | Google ブランド | CF ブランド(かつシンプル) |
実装
1. Cloudflare 側
# wrangler.toml
[[env.production.r2_buckets]]
name = "TURNSTILE_SECRET_KEY"
binding = "TURNSTILE_SECRET_KEY"
[env.production.vars]
TURNSTILE_SITE_KEY = "1x..."
2. フロント(Astro コンポーネント)
---
import { TURNSTILE_SITE_KEY } from 'astro:env/client';
---
<form id="contact-form">
<input type="email" name="email" required />
<textarea name="message" required></textarea>
<!-- Turnstile ウィジェット -->
<div class="cf-turnstile" data-sitekey={TURNSTILE_SITE_KEY}></div>
<button type="submit">送信</button>
</form>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
<script>
document.getElementById('contact-form')?.addEventListener('submit', async (e) => {
e.preventDefault();
const token = window.turnstile.getResponse();
if (!token) {
alert('Please complete the verification');
return;
}
const formData = new FormData(e.target);
formData.append('cf-turnstile-response', token);
await fetch('/api/contact', {
method: 'POST',
body: new URLSearchParams(formData)
});
});
</script>
3. バック(Pages Functions)
// functions/contact.ts
export const onRequest: PagesFunction = async (context) => {
const formData = await context.request.formData();
const token = formData.get('cf-turnstile-response');
// Turnstile トークン検証
const verifyUrl = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
const verifyResponse = await fetch(verifyUrl, {
method: 'POST',
body: JSON.stringify({
secret: context.env.TURNSTILE_SECRET_KEY,
response: token
})
});
const data = await verifyResponse.json();
if (!data.success) {
return new Response('Verification failed', { status: 400 });
}
// フォーム処理続行...
};
メリット
- プライバシー: Google と通信なし
- 速度: Cloudflare エッジで即座に検証
- 一体性: Pages + Turnstile で CF 内完結
- UI/UX: Turnstile のキャプチャがシンプル
移行時の注意
- Turnstile は reCAPTCHA v3(スコアベース)ではなく v2 相当(チャレンジベース)
- 既存のスコアロジックがあれば別途実装が必要