お問い合わせフォームや資料請求フォームは、Webサイトに欠かせない機能です。ただ、便利な反面スパムの温床になりやすいのが悩みどころ。
最近はAIや自動化ツールを使ったスパムボットも登場していて、日本語サイトへの被害も増えています。「ある日突然、英語の迷惑メールが大量に届くようになった」「意味不明な文字列ばかりが送られてくる」——そんな経験に心当たりはないでしょうか。
私がフォームのスパム対策でよく使っているのが、ハニーポットと高速送信(タイムトラップ)の合わせ技です。ざっくり言うと、こういう仕組みです。
- ハニーポット:ユーザーには見えないフィールドを仕込んでボットを引っかける
- 高速送信対策:人間の入力スピードでは不可能な高速送信をブロックする
この記事では、PHPで実装するハニーポット+高速送信対策の方法と注意点を、そのままコピペで使えるコード付きで解説します。「最近スパムが増えて困っている」「手軽にフォームのセキュリティを上げたい」という方の参考になればうれしいです。
ハニーポットとは?なぜ有効なのか
仕組みはとてもシンプルで、ハニーポットはフォーム内に「ユーザーには見えない」ダミーの入力フィールドを仕込む方法です。一般的なHTMLはこんな形になります。
<div aria-hidden="true" style="display: none;">
<label for="honeypot">自由記述欄</label>
<input type="text" id="honeypot" name="honeypot" tabindex="-1" autocomplete="off">
</div>
display: none を指定しているので、このフィールドは画面に表示されません。加えて aria-hidden="true" でスクリーンリーダーからも隠し、tabindex="-1" でキーボードのタブ移動でも触れないようにしています。autocomplete="off" を付けておくのは、ブラウザの自動入力が誤ってこの欄を埋めてしまうのを防ぐためです。ここまでやっておくと、実際のユーザーがうっかり入力してしまう事故をほぼ避けられます。
一方でボットはHTMLソースを機械的に解析し、見た目に関係なく全フィールドへ入力する傾向があります。つまり、この honeypot に何か値が入っていたらスパムだと判断できるわけです。
実際にどう判定する?
PHP側のチェックもシンプルです。フォームが送信されたときに「honeypot という名前のフィールドに値が入っていないか」を確認するだけ。以下がその具体例です。
<?php
$honeypot = isset($_POST['honeypot']) ? trim($_POST['honeypot']) : '';
if (!empty($honeypot)) {
header('Location: error.html');
exit;
}
?>
このたった数行で、機械的に送信してくるボットの大半をシャットアウトできます。軽量なのでサーバーへの負荷もほとんどありません。
高速送信(タイムトラップ)対策とは?
最近のボットにはハニーポットを回避するものも登場しています。そこで追加の対策として有効なのが「高速送信チェック」です。
フォームが表示されてから送信されるまでの経過時間を測り、たとえば 5秒未満 の送信はスパムと判定する、という仕組みです。
HTML側の実装例
フォーム内に hidden フィールドを追加し、JavaScriptでページ表示時のUNIXタイムを入れておきます。
<input type="hidden" name="FormDisplayTime" id="FormDisplayTime">
<script>
window.onload = function() {
var now = Math.floor(Date.now() / 1000); // UNIXタイム
document.getElementById("FormDisplayTime").value = now;
};
</script>
PHP側のチェック例
<?php
$formDisplayTime = isset($_POST['FormDisplayTime']) ? (int)$_POST['FormDisplayTime'] : 0;
$currentTime = time();
$elapsedSeconds = $currentTime - $formDisplayTime;
if ($elapsedSeconds < 5) {
header('Location: error.html');
exit;
}
?>
やっていることはこれだけです。JavaScriptが有効なときにだけ動くので、人間がふつうに入力して送信するぶんには問題ありません。
ひとつ知っておきたいのが、この方式は表示時刻をクライアント側で作り、それをPOSTデータに含めて送っている点です。手軽な反面、賢いボットは FormDisplayTime にわざと古い値を入れて経過時間を水増しし、チェックをすり抜けることも理屈のうえでは可能です。より厳密にやるなら、フォームを表示した時刻をサーバー側のセッション($_SESSION)に保存し、送信時にそれと突き合わせる方法が確実です。とはいえ、ハニーポットと組み合わせる前提であれば、まずはこのシンプルな実装でも十分に効果があります。
ハニーポット+高速送信対策の完全コード例
HTML
<form action="contact.php" method="post">
<input type="text" name="name" placeholder="お名前">
<input type="email" name="email" placeholder="メールアドレス">
<!-- ハニーポット -->
<div aria-hidden="true" style="display: none;">
<label for="honeypot">自由記述</label>
<input type="text" id="honeypot" name="honeypot" tabindex="-1" autocomplete="off">
</div>
<!-- タイムトラップ -->
<input type="hidden" name="FormDisplayTime" id="FormDisplayTime">
<script>
window.onload = function() {
var now = Math.floor(Date.now() / 1000); // UNIXタイム
document.getElementById("FormDisplayTime").value = now;
};
</script>
<button type="submit">送信する</button>
</form>
PHP
<?php
// ハニーポットチェック
$honeypot = isset($_POST['honeypot']) ? trim($_POST['honeypot']) : '';
if (!empty($honeypot)) {
header('Location: error.html');
exit;
}
// タイムトラップチェック
$formDisplayTime = isset($_POST['FormDisplayTime']) ? (int)$_POST['FormDisplayTime'] : 0;
$currentTime = time();
$elapsedSeconds = $currentTime - $formDisplayTime;
if ($elapsedSeconds < 5) {
header('Location: error.html');
exit;
}
// 本来の処理(メール送信など)
$to = "example@example.com";
$subject = "お問い合わせがありました";
$message = "お名前: " . $_POST['name'] . "\n";
$message .= "メールアドレス: " . $_POST['email'] . "\n";
$headers = "From: " . $_POST['email'] . "\r\n";
if (mail($to, $subject, $message, $headers)) {
header('Location: thanks.html');
} else {
header('Location: error.html');
}
exit;
?>
なお、上のPHPはスパム対策の流れをわかりやすく見せるための最小構成です。実運用では、$_POST の値をそのままメールに使うとヘッダインジェクションなどの温床になりかねないので、メールアドレスの形式チェックや改行コードの除去、htmlspecialchars() によるエスケープといった入力のバリデーションも必ず入れておいてください。
ハニーポットと高速送信対策フォーム導入まとめ
ハニーポットは、もっとも手軽に導入できるスパム対策です。
画像認証と違ってサイトの見た目やユーザー操作に影響せず、通常の利用者はまったく違和感なくフォームを使えるのが利点。HTMLを数行加えるだけで済むので、はじめての方にもおすすめできます。古くから使われている方法ですが効果はいまだ高く、単純なボットは隠しフィールドにもデータを入れてしまうため、スパム判定がしやすいのが強みです。
ただし、最近の高性能なスパムボット(AI型やカスタマイズ型)はHTML構造を解析して、こうしたダミーフィールドをスキップしてくるケースもあります。そのため「ハニーポットだけ」で完璧に防げるわけではありません。
もう一方のタイムトラップは、フォームが表示されてから送信されるまでの「人間らしい操作時間」に着目した対策です。
通常のユーザーならフォームを開いてから送信まで少なくとも数十秒はかかりますが、スパムボットは1秒もかけずに送ってくることがあります。この挙動を逆手に取り、異常に速い送信をブロックするのがタイムトラップの役割です。「見える/見えない」という仕掛けではなく行動パターンそのものを基準にするので、より進化したボットにも効きます。ただしJavaScriptが無効な環境では判定が甘くなりますし、しきい値(何秒未満をブロックするか)はフォーム内容やユーザー層に合わせて調整が必要です。
両者は性質の異なる対策なので、「ハニーポット+タイムトラップ」を併用することで、より幅広いスパムをカバーできます。まずはこの2つを入れておけば、フォームに届く迷惑メールはぐっと減らせるはずです。