このチュートリアルでは、既存の認証システムに Cloudflare Turnstile、Web Application Firewall(WAF)、Bot Management を組み込みます。自動化攻撃や悪意のあるログイン試行など、さまざまな脅威に対する多層防御を構築できます。
WAF と Bot Management を使うには、サイトの DNS を Cloudflare 経由にする必要があります。一方、Turnstile は Cloudflare のネットワーク上にないサイトを含め、どのサイトでも単独で使えます。このチュートリアルでは 3 つの製品すべての導入を扱います。サイトが Cloudflare のネットワーク上にない場合は、Turnstile だけに絞ってもかまいません。
WAF、Bot Management、Turnstile は、アプリケーションの異なる層で動作するため、組み合わせて使えます。
- WAF はネットワークシグナルに基づいて悪意のあるトラフィックをフィルタします。
- Bot Management はリクエストを分析し、自動化された脅威を特定して緩和します。
- Turnstile はクライアント側とブラウザーのシグナルを調べ、人間のユーザーとボットを区別します。
サーバー側(WAF と Bot Management)とクライアント側(Turnstile)の対策を組み合わせると、攻撃者が回避しにくい多層防御になります。
- WAF と Bot Management を使う場合は、それらにアクセスできる Cloudflare アカウントが必要です。
- 認証を処理する、既存の JavaScript / TypeScript ベースのルートがあること。
このチュートリアルでは、Turnstile をアプリケーションへ組み込む例として、プレーン HTML の簡単なログインフォームを使います。バックエンドでは、TypeScript で書いたスタブの認証ルートがログインリクエストを処理します。言語は任意に差し替えられます。使っている言語やフレームワークが Turnstile の API へ外部 HTTP リクエストを送れるなら、Turnstile を組み込めます。
サイトが Cloudflare のネットワーク上にあり、Enterprise プランに加入している場合は、WAF と Bot Management を設定する必要があります。
-
Cloudflare ダッシュボードで、WAF ページを開きます。
WAF を開く ↗ -
Edit expression を選び、新しいカスタム WAF ルールを作成します。
- フィールド: 「Bot Score」
- 演算子: 「less than or equal to」
- 値: 「30」
- アクション: 「Managed Challenge」
この設定は、ボットスコアが低いリクエストにチャレンジを出します。ネットワークシグナルで潜在的な脅威を、アプリケーションに届く前に特定します。スコアのしきい値は、用途に合わせて変更できます。
Turnstile は、サイトが Cloudflare のネットワーク上にあるかどうかに関係なく使えます。
-
Cloudflare ダッシュボードで、Turnstile ページを開きます。
Turnstile を開く ↗ -
Add widget を選び、必要な情報を入力します。
-
Turnstile の設定にドメインを追加します。
-
Create を選びます。
Turnstile はブラウザーとクライアント側のシグナルを分析し、WAF と Bot Management によるサーバー側の検査を補完します。
サイトが Cloudflare 上にある場合は、Turnstile の設定で既存の クリアランス Cookie を使うオプションを有効にできます。この連携により、Turnstile はユーザーにチャレンジを出すかどうかを判断する材料として、クリアランス Cookie を使えます。任意ですが、すでに WAF と Bot Management を使っている場合は推奨します。
Turnstile の実装には、Turnstile ウィジェットとサーバー側の検証ロジックの 2 つが必要です。
既存のログインフォームに Turnstile ウィジェットを追加します。
<form id="login-form">
<input type="text" id="username" placeholder="Username" required />
<input type="password" id="password" placeholder="Password" autocomplete="off" required />
<div class="cf-turnstile" data-sitekey="<YOUR-SITE-KEY>"></div>
<button type="submit">Log in</button>
</form>
<script
src="https://challenges.cloudflare.com/turnstile/v0/api.js"
async
defer
></script><YOUR-SITE-KEY> を、実際の Turnstile サイトキーに置き換えます。
既存の認証ルートに、Turnstile の検証を追加します。
async function validateTurnstileToken(
ip: string,
token: string,
secret: string,
): Promise<boolean> {
const response = await fetch(
"https://challenges.cloudflare.com/turnstile/v0/siteverify",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ip, secret, response: token }),
},
);
const outcome = await response.json();
return outcome.success;
}
// Assume that this is a TypeScript route handler.
// You may replace this with a different implementation,
// based on your language or framework
export async function onRequestPost(context) {
const { request, env } = context;
const { username, password, token } = await request.json();
// Validate Turnstile token
const secretKey = env.TURNSTILE_SECRET_KEY;
const ip = request.headers.get("CF-Connecting-IP");
const turnstileValid = await validateTurnstileToken(ip, token, secretKey);
if (!turnstileValid) {
// Return back to the login page with an error message
return Response.redirect("/login", 302, {
headers: {
Location: "/login?error=invalid-turnstile-token",
},
});
}
// Perform your existing authentication logic here
const isValidLogin = await checkCredentials(username, password);
if (isValidLogin) {
return new Response(JSON.stringify({ message: "Login successful" }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
} else {
return new Response(JSON.stringify({ error: "Invalid credentials" }), {
status: 401,
headers: { "Content-Type": "application/json" },
});
}
}
async function checkCredentials(
username: string,
password: string,
): Promise<boolean> {
// Your existing credential checking logic
}この構成では、ログイン処理の前にサーバー側で Turnstile トークンを検証します。クライアント側シグナルに基づく防御が追加されます。
デプロイ後は、連携をテストしてください。ボットスコアが低いため、チャレンジは出ないことが多いです。必要に応じて追加ルールを作り、チャレンジページへ強制的にリダイレクトできます。次のような方法があります。
- 自分の IP アドレスを常にチャレンジページへ転送する WAF ルールを追加します。
?challenge=trueなどのクエリパラメーターの有無を確認する WAF ルールを追加します。
- 資格情報を確認する前に、必ずサーバー側で Turnstile トークンを検証します。
- Turnstile のシークレットキーなどの機密情報は、環境変数に保存します。
- 適切なエラー処理とログを実装し、セキュリティ上の問題を監視します。
Turnstile を WAF と Bot Management と組み合わせると、ネットワーク層でアプリケーションを守りつつ、クライアント側シグナルでもう一層の保護を追加できます。悪意のある攻撃者がログインシステムへの自動化攻撃を仕掛けることが、かなり難しくなります。
Turnstile をカスタマイズする場合は、次のリソースを参照してください。
- クライアント側レンダリング。アプリケーションの要件とユーザー体験に合わせて、Turnstile を UI のどこで、いつ描画するかをカスタマイズできます。
- サーバー側検証。Turnstile の API の動き、リクエストパラメーター、エラーコードを含む各種レスポンスの扱いを確認できます。
- Turnstile Analytics。Cloudflare ダッシュボードで Turnstile の分析を確認できます。発行されたチャレンジ数や、チャレンジ解決率(CSR) などの指標が含まれます。