はじめに
Webサイトにお問い合わせフォームを設置すると、訪問者から簡単に連絡を受け取れるようになります。
企業サイト、個人サイト、サービスサイトを問わず非常に便利な機能ですが、インターネット上に公開されたフォームは、通常の利用者だけが使用するとは限りません。
実際に運用を始めると、次のような投稿が届くことがあります。
海外からのスパム
SEO業者などからの営業投稿
Botによる自動送信
大量の連続送信
JavaScriptやSQLらしき文字列を含む投稿
不自然なURLや広告リンク
お問い合わせフォームは「誰でも入力できる公開された入力窓口」であるため、Webサイトの中でも特に外部からデータを受け取る部分です。
そのため、フォームを設置する場合は「入力された内容を受け取れればよい」だけではなく、悪意のある入力や自動送信が来ることを前提として設計する必要があります。
この記事では、お問い合わせフォームで実際に起こりやすい問題と、その対策について整理します。
お問い合わせフォームには何が送られてくるのか
お問い合わせフォームに対する迷惑行為は、大きく分けると次のように整理できます。
| 種類 | 主な内容 |
|---|---|
| スパム | 広告、URL、詐欺サイトなどへの誘導 |
| 営業投稿 | SEO、Web制作、営業代行などの営業活動 |
| Bot送信 | プログラムによる自動投稿や大量送信 |
| 攻撃的な入力 | XSSやSQLインジェクションなどを狙った文字列 |
| 不正利用 | フォームやAPIを本来の用途以外で利用する行為 |
重要なのは、これらが必ずしも別々に行われるわけではないことです。
例えば営業投稿であっても、実際には人間が1件ずつ送信しているのではなく、自動化されたBotが大量のWebサイトを巡回して、お問い合わせフォームを見つけ次第送信しているケースがあります。
つまり、
営業投稿
+
Botによる自動送信
という組み合わせも珍しくありません。
1. 広告・リンクを送りつけるスパム
お問い合わせフォームで比較的分かりやすいのが、広告や外部サイトへのリンクを含むスパム投稿です。
例えば次のような内容です。
Hello,
I visited your website and noticed it is not ranking well.
We offer cheap SEO backlinks.
Visit:
https://spam-example.invalid/
あるいは、
Great website!
Check our casino site:
https://casino-example.invalid/
といった投稿です。
目的はさまざまですが、
SEOサービスの宣伝
アフィリエイトサイトへの誘導
オンラインカジノなどへの誘導
詐欺サイトへの誘導
不審なサイトへのリンク設置
などがあります。
お問い合わせ内容をWebページ上に自動公開するシステムの場合には、リンクを残すこと自体が目的になるケースも考えられます。
通常のお問い合わせフォームでは投稿内容がそのまま一般公開されることは少ないため、単純な広告活動として大量送信されるケースもあります。
2. お問い合わせフォームを利用した営業投稿
日本語のお問い合わせフォームでは、営業目的の投稿もよく見られます。
例えば、
件名:御社サイトの集客改善について
突然のご連絡失礼いたします。
弊社ではSEO対策およびWebマーケティング支援を行っております。
御社Webサイトを拝見し、
検索順位改善のお手伝いが可能ではないかと思い、
ご連絡いたしました。
一度お打ち合わせのお時間をいただけませんでしょうか。
といった内容です。
よくある分野としては、
SEO対策
Web制作
営業代行
採用支援
広告運用
マーケティング
システム開発
などがあります。
もちろん、すべての営業投稿が不正行為というわけではありません。
問題になるのは、プログラムを使用して不特定多数のWebサイトへ大量送信しているケースです。
なぜ大量の営業投稿が届くのか
Web上には、企業サイトなどを自動巡回して情報を収集するプログラムがあります。
例えば、次のような処理を自動化することができます。
Webサイトを巡回
↓
お問い合わせページを探す
↓
form要素を解析
↓
名前・メール・本文欄を推測
↓
営業文章を自動入力
↓
送信
この処理をプログラム化すれば、人間が1件ずつお問い合わせフォームを開かなくても大量のサイトへ投稿できます。
そのため、フォームをインターネット上に公開した時点で、自動送信の対象になる可能性があると考えておいた方が安全です。
3. Botによる大量送信
お問い合わせフォームでは、短時間に同じような内容が繰り返し送信されることがあります。
Webサーバーのアクセスログを見ると、例えば次のような状態になります。
POST /contact
POST /contact
POST /contact
POST /contact
POST /contact
通常の利用者であれば、数秒間に何十回もお問い合わせを送信することはありません。
一方、プログラムから直接HTTPリクエストを送信すれば、短時間に大量のリクエストを発生させることができます。
このようなBot送信によって、
大量の迷惑データが保存される
メール通知が大量に発生する
Googleスプレッドシートなどに不要なデータが蓄積される
外部APIの利用回数を消費する
サーバー負荷が高くなる
といった問題が発生する可能性があります。
そのため、フォームでは「正しい形式のデータか」だけでなく、送信頻度が異常ではないかも確認する必要があります。
4. XSSを狙った入力
お問い合わせ内容に、次のような文字列が入力されることがあります。
<script>alert('xss')</script>
これを入力されたからといって、その時点でXSSが成立するわけではありません。
問題になるのは、受け取った文字列を管理画面などへ表示するときに、HTMLとしてそのまま出力してしまった場合です。
例えば、安全ではない方法で、
<div>
ユーザーが入力した内容
</div>
の中へ入力値をHTMLとして直接挿入すると、悪意のあるコードがブラウザで実行される可能性があります。
これがクロスサイトスクリプティング、いわゆるXSSです。
そのため重要なのは、
入力時にチェックする
+
出力時に適切にエスケープする
ことです。
特に「入力チェックをしているから安全」という考え方は危険です。
入力値は原則として信頼せず、HTMLとして表示するときには、その出力先に応じた適切なエスケープやサニタイズを行う必要があります。
5. SQLインジェクションを狙った入力
データベースを利用するお問い合わせシステムでは、SQLインジェクションについても考える必要があります。
例えば入力欄に、
' OR 1=1 --
といった文字列が送信される場合があります。
問題になるのは、入力された文字列を使ってSQLを直接組み立てている場合です。
例えば概念的には、
SELECT * FROM users WHERE name = '入力値'
というSQLへ入力値を文字列連結してしまうような実装です。
悪意のある入力によってSQLそのものの意味を変更される可能性があります。
SQLインジェクション対策では、単純に特定文字を削除する方法ではなく、プリペアドステートメント(パラメータ化クエリ)を利用することが基本です。
考え方としては、
SQL文
と
入力データ
を分離する
ということです。
これによって、入力された文字列がSQL命令として解釈されることを防ぎます。
6. CSRFは「別サイトから送信されること」そのものではない
Webセキュリティの記事ではCSRFもよく登場します。
CSRFは、
利用者がログインしているWebサービスに対して、第三者のサイトなどから利用者の意図しない操作を実行させる攻撃
です。
例えば、利用者がログイン中のサービスに、
設定変更
パスワード変更
送金
データ削除
などの操作があり、そのリクエストが「本当に利用者本人が操作したものなのか」を確認していない場合に問題になります。
したがって、誰でも利用できる一般的なお問い合わせフォームに対する単なる外部サイトからのPOST送信を、すべてCSRFと呼ぶのは正確ではありません。
お問い合わせフォームでは、
他サイトからの送信
Botからの直接HTTP送信
大量投稿
APIの不正利用
とCSRFを区別して考える必要があります。
一方、ログインユーザー専用フォームや管理画面など、Cookieによる認証状態を利用して重要な処理を実行する機能では、CSRF対策が重要になります。
お問い合わせフォームはどう守ればよいのか
お問い合わせフォームでは、1種類の対策だけですべての攻撃を防ぐことはできません。
複数の対策を組み合わせる必要があります。
代表的なものを整理すると次のようになります。
| 対策 | 主な目的 |
|---|---|
| サーバー側入力検証 | 不正・異常な入力の拒否 |
| ハニーポット | 単純なBotの検出 |
| 送信時間チェック | 高速な自動送信の検出 |
| Rate Limit | 短時間の大量送信を制限 |
| CAPTCHA等 | Botと人間の判定補助 |
| 出力エスケープ | XSS対策 |
| プリペアドステートメント | SQLインジェクション対策 |
| Origin等の確認 | 想定外サイトからの利用を減らす補助 |
| CSRFトークン | 認証を伴う重要操作のCSRF対策 |
| ログ監視 | 不正利用の発見と調査 |
それぞれ役割が異なります。
ハニーポット
ハニーポットは、人間には見えない入力欄をフォームに用意する方法です。
例えば、
<input type="text" name="website">
のような項目を人間からは見えない状態にしておきます。
通常の利用者は入力しません。
一方、HTMLだけを解析してすべての入力欄へ値を設定する単純なBotでは、この欄にも文字を入力することがあります。
そこで、
ハニーポットに値が入っている
↓
Botの可能性が高い
↓
送信を拒否
という判定ができます。
実装が比較的簡単で、利用者に操作を要求しない点がメリットです。
ただし、ハニーポットを認識する高度なBotも存在するため、これだけで完全に防げるわけではありません。
送信時間を確認する
人間がWebページを開いて、お問い合わせ内容を読み、名前やメールアドレス、本文を入力するには一定の時間が必要です。
例えばページを表示してから0.1秒で送信された場合、人間による操作とは考えにくくなります。
そこで、
フォーム表示時刻
↓
入力
↓
送信時刻
↓
経過時間を確認
という仕組みを使用できます。
極端に短い時間で送信された場合には、Botの可能性が高いと判断できます。
これも利用者に追加操作を要求しないため使いやすい方法です。
ただしBot側でも待機時間を入れることは可能なので、単独での防御にはなりません。
Rate Limitを設定する
大量送信への対策として非常に重要なのがRate Limitです。
例えば、
同一IPアドレスから
1分間に5回まで
などの制限を設定します。
これによって、短時間に何百件ものリクエストを送信するような攻撃を抑制できます。
ただし、IPアドレスだけで単純に制限すると、学校・企業・携帯電話網など、複数利用者が同一のグローバルIPアドレスを共有している環境で正常な利用者を巻き込む可能性があります。
そのため実際には、
IPアドレス
Cookie
セッション
リクエスト頻度
その他のBot判定
などを組み合わせることがあります。
入力バリデーションは必ずサーバー側でも行う
HTMLには、
required
maxlength
type="email"
などの入力制限があります。
しかし、これらはブラウザ側の機能です。
攻撃者はブラウザのフォームを使用せず、
curl
Python
JavaScript
専用Bot
などからAPIへ直接HTTPリクエストを送信できます。
したがって、
JavaScriptやHTMLだけで入力チェックを行ってもセキュリティ対策にはなりません。
サーバー側でも、
必須項目
最大文字数
データ型
メールアドレス形式
許容文字
URL数
リクエストサイズ
などを確認する必要があります。
「ドメイン制限」やCORSだけでは完全には防げない
APIを特定のWebサイトからだけ利用させたい場合、
Origin
Referer
CORS
などを利用する方法があります。
ただし、これらを「API認証」と考えるのは危険です。
CORSは主に、ブラウザ上のJavaScriptが別オリジンのリソースへアクセスできるかを制御する仕組みです。
攻撃者がブラウザを使用せず、
curl
Python
独自プログラム
から直接APIへHTTPリクエストを送れば、ブラウザのCORS制御そのものは働きません。
そのため、
CORSを設定した
=
APIを外部から呼び出せなくなった
ではありません。
OriginやRefererの確認は有効な補助対策ですが、Rate Limitやサーバー側検証などと組み合わせる必要があります。
APIキーをHTMLに書けば安全、ではない
APIキーについても注意が必要です。
例えば、
const API_KEY = "abcdefg...";
のようにHTMLやJavaScriptへ直接書いたAPIキーは、Webサイトを閲覧した利用者から確認できます。
ブラウザへ送った情報を完全な秘密にすることはできません。
そのため、秘密として扱う必要があるキーは、
ブラウザ
↓
自分のサーバー
↓
外部サービス
という構成にして、サーバー側で管理するのが基本です。
一方、Google Mapsなど、ブラウザで利用することを前提としたAPIキーでは、キー自体を完全に秘密にするのではなく、
利用可能なWebサイト
利用可能なAPI
利用量
などを制限する仕組みが用意されています。
つまり、APIキーは種類や用途によって扱い方が異なります。
CAPTCHAは必要なのか
Bot対策として有名なのがreCAPTCHAなどの仕組みです。
CAPTCHAを導入するとBot対策を強化できますが、
利用者の操作が増える場合がある
外部サービスへの依存が増える
JavaScriptが増える
プライバシー面を考慮する必要がある
などの点もあります。
そのため、小規模なフォームであれば、
ハニーポット
+
送信時間
+
Rate Limit
+
サーバー側入力検証
で運用し、スパムの状況に応じてCAPTCHAを追加する方法もあります。
最初から1つの仕組みに頼るのではなく、複数の軽量な対策を重ねる考え方が重要です。
私が作ったお問い合わせ連携サービスでも複数の対策を実装
私が作成している、お問い合わせ内容をGoogleスプレッドシートへ転送するサービスでも、公開フォームをそのまま転送するのではなく、複数のチェックを行う構成にしています。
例えば、
| 対策 | 目的 |
|---|---|
| ハニーポット | Bot送信の検出 |
| 送信時間チェック | 高速な自動送信の検出 |
| 入力検証 | 異常なデータの拒否 |
| 許可ドメインの確認 | 想定外サイトからの利用を抑制 |
| API利用制御 | 転送APIの不正利用防止 |
| サーバー側処理 | スプレッドシート情報などをブラウザへ直接公開しない |
といった対策を組み合わせています。
もちろん、これらを実装したからといって、すべての迷惑投稿を100%防げるわけではありません。
Bot側も対策を回避する方法を変化させるためです。
重要なのは、
1種類の判定に依存せず、複数の条件を組み合わせて不正なリクエストを減らすこと
だと考えています。
お問い合わせフォームで最低限行いたい対策
自分でお問い合わせフォームを作成する場合、最低限確認しておきたい項目をまとめると次のようになります。
HTTPSを使用する
サーバー側で入力値を検証する
文字数やリクエストサイズを制限する
HTMLへ表示するときは適切にエスケープする
DBアクセスではプリペアドステートメントを使用する
短時間の大量送信をRate Limitで制限する
Bot対策を導入する
エラー内容を利用者へ詳細に公開しない
ログを保存して異常なアクセスを確認できるようにする
フォームがメールを送信する仕組みであれば、メールヘッダーインジェクションや大量メール送信への悪用についても確認が必要です。
まとめ
お問い合わせフォームは非常に便利ですが、インターネットへ公開した時点で、正常な利用者以外からアクセスされる可能性があります。
実際に想定しておくべきものとして、
広告スパム
営業投稿
Bot送信
大量送信
があります。
さらに、システムの実装に脆弱性が存在すれば、
XSS
SQLインジェクション
CSRF
などの問題につながる可能性もあります。
大切なのは、
「怪しい文字列を禁止する」だけでセキュリティ対策を終わらせないことです。
お問い合わせフォームには、
サーバー側入力検証
ハニーポット
送信時間チェック
Rate Limit
出力時のエスケープ
プリペアドステートメント
必要に応じたCAPTCHA
ログ監視
など、それぞれ目的の異なる対策を組み合わせる必要があります。
お問い合わせフォームは小さな機能に見えますが、外部から自由にデータを送信できる以上、Webアプリケーションにおける立派な「入口」です。
公開する以上は、
「普通の利用者だけが使う」という前提ではなく、「Botや不正な入力も必ず来る」という前提で設計する。
これが基本的な考え方になります。

0 件のコメント:
コメントを投稿