誰も見ていない攻撃は、サイトの問い合わせフォームからやってくる
問い合わせフォームは無害に見える。だが最も開けっ放しの扉であり、施錠する人はほとんどいない。
誰もがログインを守る。だが問い合わせフォームは誰も見ない。それでいて、認証もなく、摩擦もなく、送信回数の制限すらないまま、誰からの入力でも受け付けてしまう。
攻撃者が狙うのは、まさにこの非対称性だ。メールサーバーと、データベースと、あるいは内部のWebhookと会話するテキストボックス。あなたには「メッセージ」欄に見える。相手にはコマンドラインに見える。
なぜこの標的はこれほど魅力的なのか
問い合わせフォームは、同じ場所に三つの珍しい性質を備えている。信頼できない入力を受け付ける。サーバー側でロジックを走らせる。そしてほとんど監査されない。開発者はメッセージがメールに届くことだけを確認した。そこで手を止めた。
問題は「メッセージがメールに届く」という一文が、経路の全体を覆い隠している点だ。ユーザーのテキストはSMTPヘッダーの中に組み込まれ、クエリに連結され、あるいは第三者のサービスへ送られる。その境界の一つひとつが、注入の機会になる。
メールヘッダーインジェクション
古典的な手口はemail header injectionと呼ばれる。「件名」や「送信者」の欄をそのままメッセージのヘッダーに貼り付ければ、攻撃者は改行を書き込み、自分のヘッダーを追加できる。たとえば千件のアドレスへのBccを。
気づけば、あなたのサーバーがスパムを送っている。たまたまあなたの名を騙るのではなく、文字どおりあなたのインフラから、あなたのIPとドメインで送られる。結果は見えている。大手プロバイダはあなたのドメインをスパム源として扱い、あなたの業務メールはどこにも届かなくなる。
コードに化けるテキスト
さらに悪い筋書きもある。クエリをパラメータ化せずにメッセージをデータベースへ保存すれば、SQLインジェクションの扉が開く。HTMLをエスケープせずに管理画面へメッセージを表示すれば、チームがそのリードを開いた瞬間、攻撃者が仕込んだスクリプトがブラウザで走る。これが格納型XSSであり、最も過小評価されている経路の一つだ。
この共通点に注目してほしい。どの例でも攻撃者は何も「侵入」していない。フォームを、設計どおりのやり方で使っただけだ。この脆弱性は奇抜な欠陥ではない。単純な原則の欠落だ。入ってくるものを決して信じるな。
優先順位ごとの対処法
この問題の九割を塞ぐのに、WAFもセキュリティコンサルタントもいらない。必要なのは四つの点での規律だ。
- ブラウザではなく、必ずサーバーで検証する。フロントエンドの検証はユーザーへの配慮であって、セキュリティではない。攻撃者はフォームを使わず、エンドポイントに直接POSTする。
- 出力時に必ずエスケープする。データベースへ書き込むときはパラメータ化クエリを使う。画面に表示するときはHTMLをエスケープする。すべてのメッセージを、証明されるまで敵対的なものとして扱う。
- ヘッダー欄の改行を拒否する。件名、名前、メールに\rや\nが含まれる理由はない。SMTPに触れる前に取り除く。
- 送信回数を制限し、見えない関門を加える。IPごとのレート制限と、honeypotまたはhCaptchaが、人間の体験を損なわずに自動ボットを止める。
そして、ほぼ誰もが忘れる側面
問い合わせフォームは個人データを収集する。名前、メール、しばしば電話番号、そしてメッセージの中身。それだけであなたは、好むと好まざるとにかかわらずGDPRの範囲内に入る。そのデータを扱うための法的根拠が要り、同意はインフォームドでなければならない。
実務では、これは三つの具体的なことを意味する。フォームに紐づいた明確なプライバシー通知。定められた法的根拠、典型的には第6条の正当な利益か、明示的な同意。そして保持ポリシーだ。リードを永遠に保管するのは戦略ではなく、積み上がる責任だからだ。リードのデータベースを盗まれれば、問題はもはや技術ではなく、規制の問題になる。
フォームのセキュリティとは、高価なファイアウォールではない。見知らぬ他人が書いたテキストを、信じることを拒む姿勢だ。— Krivar Diário
教訓は退屈だ。だからこそ効く。誰も見ていない攻撃は、誰も見ない扉からやってくる。ログインに払うのと同じ敬意を問い合わせフォームに払えば、こうした問題の大半はそもそも起きない。