¡Apuntando a cero spam! Cómo implementar un formulario que 'no comprometa la UX' con Next.js + reCAPTCHA v3 + Resend + Honeypot

¡Apuntando a cero spam! Cómo implementar un formulario que 'no comprometa la UX' con Next.js + reCAPTCHA v3 + Resend + Honeypot のビジュアル

¿Está segura la defensa contra el spam de su formulario de contacto en un sitio creado con Next.js? Este artículo explica detalladamente, con código, los pasos específicos para construir un formulario seguro que funcione 'correctamente' en Next.js (App Router), combinando reCAPTCHA v3 (que no compromete la UX), Resend (para un envío de correo electrónico sencillo) y Honeypot (clásico pero efectivo).

  • スパム対策の課題従来のv2チェックボックスはUXを損ない、対策なしではビジネスリスクが増大する。
  • 本記事のゴールNext.js環境で、UXを維持しつつ強力なスパム防衛線(reCAPTCHA v3, Resend, Honeypot)を構築する。
  • 主な実装ステップHoneypot設置、reCAPTCHA v3導入、Resendでのメール送信、Server Actionsでの連携までを解説。

お問い合わせフォームの「スパム問題」、まだ放置していませんか?

Next.jsによる高速なWebサイト構築が主流となる中、ビジネスの窓口である「お問い合わせフォーム」の重要性は変わりません。しかし、このフォームは常にボットによるスパム(迷惑行為)の標的となっています。

フォームを設置したものの、毎日大量のスパムメールが届き、本当に重要なリード(見込み客)からのお問い合わせが埋もれてしまう…。そんな経験をお持ちの開発者やWeb担当者も多いのではないでしょうか。

従来のスパム対策(v2チェックボックス)の限界

「私はロボットではありません」でお馴染みのGoogle reCAPTCHA v2(チェックボックス式)は、長らくスパム対策のデファクトスタンダードでした。しかし、これには大きな欠点があります。

  • UXの悪化: ユーザーに「クリック」や「画像選択」という余計な操作を強いるため、フォーム送信の離脱率(CVRの低下)に繋がります。
  • 対策の陳腐化: 近年では、AIの進化によりv2チェックボックスを突破するボットも増えています。

Next.js時代の「スマートな」スパム対策とは?

現代のWeb開発、特にNext.jsのようなフレームワークを使う場合、UXを最優先に考えるべきです。ユーザーにストレスを感じさせず、水面下でボットを判定する「スマートな」対策が求められます。

本記事で提案するのは、まさにそのアプローチです。UXを一切損なわずに、複数の防衛線を張ることで、フォームのセキュリティを格段に高めます。

スパム対策の甘さが招く、深刻なビジネスリスク

「少しぐらいスパムが来ても、手動で削除すればいい」と考えるかもしれません。しかし、対策の甘さは、目に見えないところで深刻なビジネスリスクを引き起こします。

機会損失:本物の問い合わせがスパムに埋もれる

最大の損失はこれです。1日に100件のスパムが届けば、その中に紛れ込んだ「1件の貴重な商談」を見逃すリスクは飛躍的に高まります。営業担当がスパムの仕分けに疲弊し、結果として迅速な顧客対応(リードへのレスポンス)ができなくなるのです。

サーバー負荷とセキュリティ懸念

大量のボットアクセスは、無駄なサーバーリソースを消費します。また、悪意のあるスクリプトがフォームを通じて送信される(メールヘッダーインジェクションなど)可能性もゼロではなく、セキュリティ上の懸念も残ります。

「ちゃんとした」フォームとは、単にメールが送れるだけでなく、こうしたビジネスリスクを未然に防ぐ仕組みが組み込まれたフォームのことを指します。

解決策:Next.js + 3つの防衛線で「ちゃんとした」フォームを作る

そこで本記事では、Next.js (App Router) 環境を前提に、以下の3つの技術を組み合わせて「UXを損なわない」強力なスパム対策を実現します。

なぜこの3つ? 各技術の役割

1. Honeypot (ハニーポット)

役割:最も単純なボットの排除
人間には見えない(CSSで隠す)入力フィールドをフォームに設置します。人間は入力しないため、このフィールドに値が入っていたら、それはボットだと判断できます。古典的ですが、単純なボット対策に非常に有効です。

2. Google reCAPTCHA v3

役割:高度なボットの判定
v2とは異なり、ユーザーに操作を強いることなく、サイト上での行動(マウスの動き、クリックパターンなど)を分析し、「人間らしさ」をスコア(0.0〜1.0)で判定します。このスコアが低い(ボットの可能性が高い)リクエストを弾くことができます。

3. Resend

役割:確実なメール送信と開発体験の向上
モダンなメール送信APIサービスです。従来のSMTP設定の煩雑さから開発者を解放し、シンプルなAPIコールでメール送信を実現します。Next.jsとの親和性が非常に高いのも特徴です。

これらを組み合わせることで、「単純なボットはHoneypotで弾き、高度なボットはreCAPTCHA v3で弾き、人間からの(と判断された)リクエストのみをResendで処理する」という多層防御が完成します。

実装ガイド:Next.js (App Router) での構築ステップ

ここからは、Next.jsのApp RouterとServer Actionsを使い、具体的な実装手順を解説します。コードは簡潔化していますが、実際のプロジェクトに応用できるはずです。

ステップ1:環境構築とライブラリの準備

まず、必要なライブラリをインストールします。reCAPTCHA v3の実行には google-recaptcha-v3、Resendの利用には resend を使います。フォームのバリデーションには zod が便利です。


npm install resend zod google-recaptcha-v3
    

また、環境変数 (`.env.local`) に各種シークレットキーを登録しておきます。


# .env.local
RESEND_API_KEY=re_xxxxxxxxxxxx
RECAPTCHA_V3_SECRET_KEY=xxxxxxxxxxxx
NEXT_PUBLIC_RECAPTCHA_V3_SITE_KEY=xxxxxxxxxxxx
    

ステップ2:Honeypot(ハニーポット)の実装

フォームコンポーネントに、ボットを罠にかけるためのHoneypotフィールドを追加します。`position: absolute` と opacity: 0 などで、人間のユーザーには絶対に見えない・操作できないようにCSSで隠すのが一般的です。


// components/ContactForm.jsx

// ...(フォームの他の部分)

{/* Honeypot Field: 見えないようにCSSで隠す */}
<div style={{ position: 'absolute', left: '-5000px', opacity: '0' }} aria-hidden="true">
  <label htmlFor="honeypot">Bot detected</label>
  <input type="text" id="honeypot" name="honeypot" tabIndex={-1} autoComplete="off" />
</div>

// ...
    

サーバーサイド(Server Actions)では、この honeypot フィールドに値が入っていたら、即座に処理を中断します。

ステップ3:Google reCAPTCHA v3 の設定と導入

reCAPTCHA v3は、フロントエンドでトークンを取得し、バックエンド(Server Actions)でそのトークンを検証する流れになります。

まず、reCAPTCHA v3のプロバイダーでアプリケーションをラップします。(`layout.tsx` など)


// app/layout.tsx
import { GoogleReCaptchaProvider } from 'google-recaptcha-v3';

export default function RootLayout({ children }) {
  const siteKey = process.env.NEXT_PUBLIC_RECAPTCHA_V3_SITE_KEY || '';
  return (
    <html>
      <body>
        <GoogleReCaptchaProvider reCaptchaKey={siteKey}>
          {children}
        </GoogleReCaptchaProvider>
      </body>
    </html>
  );
}
    

次に、フォーム送信時にトークンを取得し、フォームデータと一緒に送信します。`useGoogleReCaptcha` フックを使います。


// components/ContactForm.jsx ('use client')
import { useGoogleReCaptcha } from 'google-recaptcha-v3';

export default function ContactForm() {
  const { executeRecaptcha } = useGoogleReCaptcha();

  const handleSubmit = async (formData) => {
    if (!executeRecaptcha) {
      console.error("reCAPTCHA not initialized");
      return;
    }

    try {
      // reCAPTCHAトークンを取得
      const token = await executeRecaptcha('contactForm');
      
      // Server Actionsにフォームデータとトークンを渡す
      const result = await sendEmailAction(formData, token);
      // ...(結果に応じた処理)
      
    } catch (error) {
      // ...(エラー処理)
    }
  };

  return (
    <form action={handleSubmit}>
      {/* ... フォーム項目 ... */}
      {/* ... Honeypotフィールド ... */}
      <button type="submit">送信</button>
    </form>
  );
}
    

ステップ4:Resend によるメール送信 API の設定

Resendを使ったメール送信ロジックは非常にシンプルです。Server Actions内で実行します。


// app/actions.ts ('use server')
import { Resend } from 'resend';

const resend = new Resend(process.env.RESEND_API_KEY);

export async function sendEmail(payload) {
  try {
    const { data, error } = await resend.emails.send({
      from: '自社サイト通知 <noreply@example.com>',
      to: ['your-support-email@example.com'], // お問い合わせの受信先
      subject: `【お問い合わせ】${payload.name}様より`,
      react: <EmailTemplate name={payload.name} email={payload.email} message={payload.message} />, // ResendはReactコンポーネントでメールテンプレートを書けます
    });

    if (error) {
      throw new Error("Email sending failed");
    }
    return { success: true, data };
  } catch (error) {
    return { success: false, error: error.message };
  }
}
    

ステップ5:Server Actions で全てを連携させる(バリデーションと実行)

最後に、Server Actions(`app/actions.ts`)で、Honeypotチェック、reCAPTCHA v3検証、Zodバリデーション、メール送信をすべて繋ぎ込みます。


// app/actions.ts ('use server')
import { z } from 'zod';
import { Resend } from 'resend';
// (sendEmail関数は上記ステップ4のものを想定)

// Zodスキーマ定義
const FormSchema = z.object({
  name: z.string().min(1, 'お名前は必須です'),
  email: z.string().email('有効なメールアドレスを入力してください'),
  message: z.string().min(10, '内容は10文字以上で入力してください'),
});

// reCAPTCHA v3 検証関数
async function verifyRecaptcha(token) {
  const secretKey = process.env.RECAPTCHA_V3_SECRET_KEY;
  const response = await fetch(`https://www.google.com/recaptcha/api/siteverify`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: `secret=${secretKey}&response=${token}`,
  });
  const data = await response.json();
  
  // スコアが低い(例: 0.5未満)または失敗した場合はボットと判断
  return data.success && data.score >= 0.5;
}


// メインのServer Action
export async function sendEmailAction(formData, recaptchaToken) {
  // 1. Honeypot チェック
  if (formData.get('honeypot')) {
    return { success: false, error: 'Bot detected' }; // ボットには失敗を悟られないよう、一般的なエラーを返しても良い
  }

  // 2. reCAPTCHA v3 検証
  const isHuman = await verifyRecaptcha(recaptchaToken);
  if (!isHuman) {
    return { success: false, error: 'reCAPTCHA verification failed' };
  }

  // 3. Zod バリデーション
  const parsed = FormSchema.safeParse({
    name: formData.get('name'),
    email: formData.get('email'),
    message: formData.get('message'),
  });

  if (!parsed.success) {
    return { success: false, error: 'Validation failed', issues: parsed.error.issues };
  }

  // 4. メールの送信(Resend実行)
  try {
    await sendEmail(parsed.data); // ステップ4で定義した関数
    return { success: true, message: 'お問い合わせありがとうございます。' };
  } catch (error) {
    return { success: false, error: 'Failed to send email' };
  }
}
    

まとめ:UXとセキュリティを両立したフォームで、信頼を勝ち取る

今回は、Next.js (App Router) 環境において、UXを損なわずに強力なスパム対策を施す方法として、HoneypotreCAPTCHA v3、そしてResendを組み合わせる手法を解説しました。

お問い合わせフォームは、お客様との最初の接点となる重要な場所です。そこにストレス(v2チェックボックス)やリスク(スパムの氾濫)があってはなりません。

本記事で紹介した実装を行うことで、ユーザーは快適に、そして運営者は安心してフォームを運用することが可能になります。ぜひ、あなたのNext.jsプロジェクトにも「ちゃんとした」フォームを実装してみてください。

Next.js開発のパートナーをお探しですか?

当社(株式会社ABC)は、Next.jsをはじめとするモダンなWeb技術を用いた高パフォーマンスなサイト構築を得意としています。

「自社サイトをNext.jsでリニューアルしたい」「セキュアなWebアプリケーション開発を依頼したい」など、Webに関するお困りごとがございましたら、お気軽にご相談ください。

専門のエンジニアが、お客様のビジネス課題に最適なソリューションをご提案します。

¿Fue útil este artículo?