ロリポップのPHPメールフォームにスパム投稿が来る時のTurnstile確認順番
久しぶりにロリポップのWebメーラーを開いたら、問い合わせフォーム経由らしきスパムメールが大量に届いていた。そんな時は、メール本文や送信処理だけでなく、フォーム送信前の確認を入れると被害を減らしやすくなります。
この記事では、無料で使えるCloudflare TurnstileをPHPメールフォームへ入れる時の考え方を、ロリポップで運用している小さなサイト向けに整理します。
確認日と対象
確認日: 2026年5月19日。ロリポップで自作PHPメールフォームを運用していて、海外スパム、URLだらけの投稿、短時間の連投が届く人向けです。
WordPressプラグイン固有の設定、Cloudflare WAF全体の設計、大量配信システムは対象外です。まずフォームにTurnstileを表示し、PHP側でトークン検証してからメール送信へ進む形にします。
Turnstileを入れる流れ
site keyでフォームに表示し、送信されたトークンをPHP側でsecret keyと一緒に検証してからメール送信へ進みます。
secret key はPHP側だけで使います。HTMLやJavaScriptに書いて公開しないでください。
Cloudflare Turnstileでできること
Cloudflare Turnstileは、問い合わせフォームなどに設置できるスパム・自動投稿対策です。reCAPTCHAの代わりとして使われることもあり、フォームにウィジェットを表示し、送信時に発行されたトークンをPHP側で検証します。
公式ドキュメントでも、クライアント側の表示だけでなくサーバー側の検証が必要と説明されています。検証先は https://challenges.cloudflare.com/turnstile/v0/siteverify です。
実際に見る順番
Turnstileは「フォームに表示しただけ」では不十分です。スパムを止めたい場合は、PHP側の検証結果でメール送信を止めるところまで確認します。
| 順番 | 見る場所 | 分かること |
|---|---|---|
| 1 | スパム投稿の内容 | URL連投、英語だけ、短時間連投などの傾向 |
| 2 | Cloudflareのsite key | フォーム表示用のキーが正しいか |
| 3 | Cloudflareのsecret key | PHP側だけで使う秘密キーがあるか |
| 4 | HTMLフォーム | cf-turnstile が送信ボタン前に表示されるか |
| 5 | POSTされたトークン | cf-turnstile-response がPHPへ届いているか |
| 6 | Siteverify APIの結果 | success がtrueの時だけ送信しているか |
| 7 | ログと追加対策 | 失敗理由、honeypot、URL数、連投制限を見られるか |
発行するキー
| キー | 使う場所 | 注意 |
|---|---|---|
| site key | HTMLフォーム側 | 公開されてもよいキー。ウィジェット表示に使う |
| secret key | PHP側 | 絶対に公開しない。Cloudflareへ検証リクエストを送る時に使う |
HTMLフォームにTurnstileを表示する
フォームの送信ボタン付近にTurnstileの表示エリアを置きます。YOUR_SITE_KEY はCloudflareで発行したsite keyに置き換えます。
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
<form action="/contact-submit.php" method="post">
<label>お名前</label>
<input type="text" name="name" required>
<label>メールアドレス</label>
<input type="email" name="email">
<label>お問い合わせ内容</label>
<textarea name="message" required></textarea>
<div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY"></div>
<button type="submit">送信する</button>
</form>
PHP側でsecret keyを使って検証する
Turnstileを表示しただけでは不十分です。送信された cf-turnstile-response をPHP側でCloudflareへ送り、success がtrueか確認してからメール送信処理へ進みます。
<?php
$turnstile_secret = 'YOUR_SECRET_KEY';
$turnstile_token = $_POST['cf-turnstile-response'] ?? '';
$verify_response = file_get_contents(
'https://challenges.cloudflare.com/turnstile/v0/siteverify',
false,
stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
'content' => http_build_query([
'secret' => $turnstile_secret,
'response' => $turnstile_token,
'remoteip' => $_SERVER['REMOTE_ADDR'] ?? null,
]),
'timeout' => 10,
],
])
);
$turnstile_result = json_decode($verify_response, true);
if (empty($turnstile_result['success'])) {
exit('セキュリティ確認に失敗しました。時間をおいて再度お試しください。');
}
// ここから先でメール送信処理を行う
?>
ロリポップで導入する時の注意点
secret keyをHTMLに書かない- フォーム送信先のPHPで必ずTurnstileの検証をする
- 検証に失敗した時はメール送信処理へ進めない
- 外部URLへ接続できない場合は、PHP設定やサーバー環境を確認する
- テスト時は自分で送信し、正常送信と失敗時の両方を見る
Turnstileだけに頼らない追加対策
スパム投稿は一つの対策だけで完全に止まるとは限りません。フォーム側では、次のような軽い対策も組み合わせると安全寄りになります。
| 対策 | 内容 |
|---|---|
| honeypot | 人には見えない入力欄に値が入っていたら拒否する |
| URL数チェック | 本文にURLが多すぎる投稿を拒否する |
| 文字数制限 | 極端に短い・長い本文を弾く |
| 連投制限 | 短時間に何度も送信される場合に止める |
| ヘッダー対策 | Fromは自分のドメイン、返信先はReply-Toに分ける |
うまく動かない時の確認
- HTML側のsite keyが正しいか
- PHP側のsecret keyが正しいか
cf-turnstile-responseがPOSTされているか- サーバー側検証のレスポンスをログで確認できるか
- トークンは時間切れや二重送信で失敗することがある
正常な問い合わせまで止めていないか確認する
Turnstileを入れた後は、スパムが減ったかだけでなく、正常な問い合わせが送信できているかも確認します。送信できたか、失敗したか、どこで止まったかを残す場合は、PHPメールフォームが送信できたか分からない時のログ確認順番も合わせて確認してください。
AIに相談する時のメモ
AIに相談する時は、site keyは貼ってもよいですが、secret keyは貼らないでください。検証結果やエラーコードだけを共有します。
ロリポップのPHPメールフォームにスパム投稿が来るため、Cloudflare Turnstileを入れています。
フォームURL:
起きている症状:
例: Turnstileを入れたのにスパムが届く / 正常送信も失敗する / tokenがPOSTされない
HTML側で確認したこと:
- api.jsを読み込んでいるか:
- cf-turnstileのdivが表示されるか:
- site keyが正しいか:
PHP側で確認したこと:
- cf-turnstile-responseが届いているか:
- siteverifyへPOSTしているか:
- successがtrueの時だけメール送信しているか:
- error-codes:
ログに残した内容:
追加対策:
- honeypot:
- URL数チェック:
- 文字数制限:
- 連投制限:
secret key、管理画面URL、個人情報は伏せています。
初心者向けに、次に見る順番を教えてください。
公式情報で確認するところ
| 確認したいこと | 公式情報 | この記事での使い方 |
|---|---|---|
| Turnstileの全体手順 | Cloudflare公式 Turnstile Get started | site key、secret key、フォームへの設置の前提を確認します。 |
| サーバー側検証 | Cloudflare公式 Validate the token | siteverify、secret、response、失敗コードの確認に使います。 |
| フォームへの表示 | Cloudflare公式 Embed the widget | HTML側の cf-turnstile とスクリプト読み込みを確認します。 |