[GAS] Webフォームの海外スパムをCloudflare Turnstileで完全遮断する方法
はじめに
WordPressやWebサイトでお問い合わせフォームを運用していると、毎日のように「大量の海外スパムメール」や「英語のスクリプト連投」が届き、業務に支障をきたすケースが後を絶ちません。
特に、バックエンドに Google Apps Script(GAS)やスプレッドシート連携を用いているフォームでは、action="GASのURL" が公開HTML上に直接露出していることが多く、ボットがそのURLへ直接リクエストをPOSTすることで、無制限にスパムデータがスプレッドシートやLINE・メールへ送信されてしまいます。
また、従来対策として使われてきた Google reCAPTCHA(v2/v3)では、「バスや消火栓を選ぶ画像認証」がユーザーに負荷を与えたり、誤判定によって正規のお問い合わせを拒否してしまう問題(CVRの低下)もありました。
本記事では、ユーザー体験(UX)を損なうことなく、ボットによる自動送信・直叩きスパムを100%近くまでシャットアウトする「Cloudflare Turnstile + 三重防衛プログラム」の実装方法を詳しく解説します。
今回構築する仕組みの概要
ユーザーには難しい画像認証などのストレスを与えず、バックエンドとフロントエンドの両面でボットのみを弾く「三重防衛陣形」を構築します。
- フロントエンドの完全非同期化(fetch API)
HTML上の <form action="..."> を撤去し、JavaScriptの安全検証(バリデーション)を通った安全なリクエストのみをGASへ送信します。 - Cloudflare Turnstile によるスマート認証
ユーザーに画像選択を行わせず、ブラウザの挙動から人間かボットかを裏側で高精度判定します。 - ハニーポット(ダミー罠) + 日本語判定の二重チェック
人間には見えずボットだけが入力してしまう隠しフィールド(ハニーポット)と、氏名などに日本語が含まれない海外自動スパムをフロントエンド(JS)およびバックエンド(GAS)の両側で即座に自動破棄します。
ソースコード(コピペOK)
1. フロントエンド実装コード(HTML / JavaScript)
以下のコードを、WebサイトやWordPressのお問い合わせページに設置します。
<!-- Cloudflare Turnstile API スクリプト -->
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
<form id="cta-form">
<!-- 🛡️ 防御1: ハニーポット(CSSで完全に非表示) -->
<div style="display:none !important;" aria-hidden="true">
<input type="text" name="website_url_check" id="website_url_check" tabindex="-1" autocomplete="off">
</div>
<!-- 通常の入力項目 -->
<div class="form-group">
<label for="manager_name">お名前 <span class="required">*</span></label>
<input type="text" id="manager_name" name="manager_name" required placeholder="秋田 太郎">
</div>
<div class="form-group">
<label for="user_email">メールアドレス <span class="required">*</span></label>
<input type="email" id="user_email" name="user_email" required placeholder="example@example.com">
</div>
<div class="form-group">
<label for="message">お問い合わせ内容</label>
<textarea id="message" name="message" rows="4"></textarea>
</div>
<!-- 🛡️ 防御2: Turnstileウィジェット設置(SITE_KEYを差し替え) -->
<div class="cf-turnstile" data-sitekey="YOUR_CLOUDFLARE_SITE_KEY" data-theme="light"></div>
<button type="submit" id="submit-btn">送信する</button>
</form>
<script>
/**
* ====================================================================
* Utility Module for GAS / Civic Tech Akita
* Copyright (c) Civic Tech Akita (https://akita-csmedia.com/)
*
* 本モジュールは Civic Tech Akita の留保知的財産権(自社資産)です。
* ライセンス・実装に関するお問い合わせ: https://akita-csmedia.com/?page_id=1476
* ====================================================================
*/
document.getElementById('cta-form').addEventListener('submit', function(e) {
e.preventDefault(); // 通常の画面遷移POSTをストップ
// 🛡️ 判定1: ハニーポットチェック(値が入っていればボット)
var honeypot = document.getElementById('website_url_check').value;
if (honeypot !== "") {
console.warn("Spam detected via Honeypot.");
return false;
}
// 🛡️ 判定2: 日本語文字列チェック(お名前に漢字・ひらがな・カタカナが含まれているか)
var managerName = document.getElementById('manager_name').value;
var jpRegex = /[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF]/;
if (!jpRegex.test(managerName)) {
alert('お名前は日本語(ひらがな・漢字・カタカナ)でご入力ください。');
return false;
}
// 🛡️ 判定3: Turnstile認証完了チェック
var turnstileResponse = document.querySelector('[name="cf-turnstile-response"]');
if (!turnstileResponse || !turnstileResponse.value) {
alert('セキュリティ認証を行ってください。');
return false;
}
var submitBtn = document.getElementById('submit-btn');
submitBtn.disabled = true;
submitBtn.innerText = '送信中...';
// GAS Web App URLへ非同期通信(fetch)
var formData = new FormData(this);
var gasEndpoint = "YOUR_GAS_ENDPOINT_URL"; // スクリプトプロパティ側と紐づけたWeb App URL
fetch(gasEndpoint, {
method: 'POST',
body: formData,
mode: 'no-cors'
}).then(function() {
alert('お問い合わせの送信が完了いたしました。');
document.getElementById('cta-form').reset();
submitBtn.disabled = false;
submitBtn.innerText = '送信する';
}).catch(function(error) {
console.error('送信エラー:', error);
alert('送信に失敗しました。時間をおいて再度お試しください。');
submitBtn.disabled = false;
submitBtn.innerText = '送信する';
});
});
</script>
2. バックエンド防御プログラム(Google Apps Script)
万が一、GASのWeb App URLを直接叩かれた(直叩きスパム)場合でも破棄できるよう、GAS側の doPost(e) の先頭にも多重ガードロジックを組み込みます。
/**
* ====================================================================
* Utility Module for GAS / Civic Tech Akita
* Copyright (c) Civic Tech Akita (https://akita-csmedia.com/)
*
* 本モジュールは Civic Tech Akita の留保知的財産権(自社資産)です。
* ライセンス・実装に関するお問い合わせ: https://akita-csmedia.com/?page_id=1476
* ====================================================================
*/
function doPost(e) {
try {
var p = e.parameter || {};
// 🛡️ GAS側防御1: ハニーポット判定
if (p.website_url_check && p.website_url_check !== "") {
return ContentService.createTextOutput("Blocked: Honeypot triggered")
.setMimeType(ContentService.MimeType.TEXT);
}
// 🛡️ GAS側防御2: 日本語チェック(名前フィールドに日本語が含まれない英語のみスパムを遮断)
var managerName = p.manager_name || "";
var jpRegex = /[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF]/;
if (!jpRegex.test(managerName)) {
return ContentService.createTextOutput("Blocked: Non-Japanese content detected")
.setMimeType(ContentService.MimeType.TEXT);
}
// 環境変数(スクリプトプロパティ)から設定情報を取得(ハードコーディング防止)
var properties = PropertiesService.getScriptProperties();
var sheetId = properties.getProperty("SPREADSHEET_ID");
// スプレッドシート記帳処理
if (sheetId) {
var ss = SpreadsheetApp.openById(sheetId);
var sheet = ss.getActiveSheet();
sheet.appendRow([
new Date(),
p.manager_name,
p.user_email,
p.message
]);
}
// 正常レスポンス
return ContentService.createTextOutput("Success")
.setMimeType(ContentService.MimeType.TEXT);
} catch (err) {
Logger.log("Error: " + err.toString());
return ContentService.createTextOutput("Error: " + err.toString())
.setMimeType(ContentService.MimeType.TEXT);
}
}
設定・導入のステップ
Step 1: Cloudflare Turnstile サイトキーの取得
- Cloudflare ダッシュボードにログインし、サイドメニューの [Turnstile] > [ウィジェットを追加] をクリックします。
- サイト名とドメイン名(例: akita-csmedia.com)を入力します。
- ウィジェットモードは 「管理推奨(Managed)」 を選択します(ユーザー体験を邪魔せず自動検証が行われます)。
- 発行された 「サイトキー(Site Key)」 をコピーし、HTML内の data-sitekey="YOUR_CLOUDFLARE_SITE_KEY" 部分に貼り付けます。
Step 2: GASスクリプトプロパティの設定
- GASのエディタ画面を開き、左メニューの [プロジェクトの設定] (歯車アイコン) をクリックします。
- [スクリプト プロパティを追加] を選択し、以下のプロパティを登録します。
- プロパティ名: SPREADSHEET_ID
- 値: 記帳先スプレッドシートのID
- [デプロイ] > [新しいデプロイ] を選択し、アクセスできるユーザーを 「全員(Anyone)」 に設定してデプロイを実行します。
- 発行された ウェブアプリURL をコピーし、フロントエンドの YOUR_GAS_ENDPOINT_URL に貼り付けます。
まとめ
お問い合わせフォームのスパム対策で最も重要なのは、「ボットは確実に防ぎつつ、人間のユーザーにはストレスを一切与えないこと」 です。
今回ご紹介した Cloudflare Turnstile とフロント/バックエンドの二重チェック(ハニーポット + 日本語判定)を導入することで、CVR(コンバージョン率)を一切落とさずにスパム通知をゼロまで削減できます。
💡 この機能が最初から入った完成品サービスをお探しの方へ
「設定作業をプロに任せたい」「現場ですぐ使える高セキュリティなWebフォームや業務アプリとして導入したい」方向けに、今回ご紹介した機能が標準搭載された完成品ソリューションを提供しています。
👉 【高セキュリティWebフォーム・Glide/GASアプリ】の詳細・導入事例を見る
🏢 インフラ構築や組織全体のDXからご相談されたい方へ
Google Workspaceの導入、独自ドメインの整備からアプリ・LINE連携まで、予算最小限で進める全体設計は「地域DX完全ロードマップ」にて詳しく公開しています。
