BLOG
Webエンジニア2025年新卒採⽤ BRISKは新卒からリモートワークです。

【PHP】セキュリティを考慮したお問い合わせフォームを作ろう!

更新日:2023/03/07

みなさん、お問い合わせフォームはどうやって作っていますか?
恐らくCMSのプラグインを使って作成することがほとんどかと思います。

ただ、ときにはスクラッチでお問い合わせフォームを作成しなければならないことがあると思います。
そこで今回はPHPを使用して、セキュリティを考慮したお問い合わせフォームを作成します。

なお、今回のお問い合わせフォームは入力ページと確認ページ、完了ページの3つに分ける想定で進めます。

もとになるHTML

まずはもとになるフォームを静的で作ります。
ということで、出来上がったフォーム部分のHTMLコードがこちらになります。

スタイルをいい感じに当てるとこのようになりました。

フォームイメージ

それではここからPHPを用いてフォームの構築を行います。

2重送信の防止

まずは2重送信の防止についてです。

概要

フォーム送信後にページをリロードした際や送信ボタンをダブルクリックした際に入力内容が再度送信されるのを防ぐため、セッションを用いて対策を行います

セッションを用いた2重送信対策は以下の通りです。

  1. 1トークンを生成
  2. 2トークンを次のページにPOST送信
  3. 3前のページから送られてきたトークンとセッション変数のトークンが一致するか判定
  4. 4トークンが一致するときはフォームのフローに沿って処理、一致しないときは入力画面に飛ばしてエラー表示

実装

それでは入力画面、確認画面、完了画面の3つに分けて処理を解説していきます。

入力画面での処理

入力画面で必要な処理は、トークンの生成と確認画面へのPOST送信です。

処理の内容としては、コメントの通りですがセッションを開始し、トークンを生成したうえでセッション変数に生成したトークンをセットするというものです。
そして、下記のようにフォームタグ内で入力内容と併せてトークンもPOST送信します。

また、確認・完了ページで行うトークン判定のところで条件が一致しなかった際にセッション変数を用いてエラー返すようにするため、下記記述を任意の場所に追記します。

これでトークンによる判定ができるのですが一点注意が必要なことがあり、PHPのセッションを開始すると一部ブラウザでブラウザバック時にフォームの入力内容が消えてしまうことがあります
これはPHPのセッションを開始すると、クライアントキャッシュが無効になるHTTPヘッダが出力されることが原因です。

そのため、下記の1行をセッション開始する前に追加することで対策します。

これで入力画面で必要な処理は以上です。
続いて、確認画面での処理です。

確認画面での処理

確認画面で必要な処理は、トークンの判定と送信です。

処理の内容としては、18行目から23行目でPOSTされたトークンとセッション変数内のトークンが一致するかどうかを判定します。
POSTされるはずのトークンが空のときPOSTされたトークンがセッショントークンと一致しないときには、不正なリクエストとしてフォームのTOPにエラーメッセージと一緒に送り返します。

POSTされたトークンとセッショントークンが一致するときには再度セッション変数にトークンをセットし、下記のように入力画面のときと同様にフォームタグ内で入力内容と併せてトークンもPOST送信します。

これで確認画面の処理まで完了しました。
最後に完了画面での処理です。

完了画面での処理

完了画面で必要な処理は、トークンの判定です。

処理の内容は確認画面とほぼ同じになりますがPOSTされたトークンとセッション変数内のトークンが一致するかどうかを判定します。
もし、POSTされるはずのトークンが空のときPOSTされたトークンがセッショントークンと一致しないときは、不正なリクエストとしてフォームのTOPにエラーメッセージと一緒に送り返します。

POSTされたトークンとセッショントークンが一致するときにはメール送信等の処理が続きます。

これで2重送信対策ができましたので実際に確認してみましょう。

動作確認

フォーム送信完了後にブラウザバックで確認画面に戻り、再度送信ボタンを押します。
すると、下記画像のようにフォームのTOPに遷移し、エラーが表示されたかと思います。

2重送信によるエラー

これで2重送信対策の完了です。

クロスサイトスクリプティング

次にクロスサイトスクリプティングの対策についてです。

概要

クロスサイトスクリプティングとは、フォームに入力した内容で不正な処理を発生させるというものです。
これはフォームから受け取った値に対して、エスケープ処理を施さずにそのまま処理することが原因です。

実際にクロスサイトスクリプティングで不正な処理を発生させてみましょう。
名前の項目にスクリプトを入力してみます。

入力項目にスクリプトを埋め込む

すると、下記のように次の確認ページ画面でお名前の値がスクリプトと解釈され、アラートが出てしまいました。

クロスサイトスクリプティング未対策の確認画面

これがクロスサイトスクリプティングの一例です。

今回はアラートでしたので特にサイトに影響はありませんが、もしサイトやサーバに影響を与えるコードが入力されたらと考えると恐ろしいですね。

ということで、クロスサイトスクリプティングの恐ろしさをご理解いただけたかと思いますので、対策をしていきましょう。

クロスサイトスクリプティングの対策

対策といってもとても簡単で、フォームから受け取った値を出力する前にエスケープ処理を施すだけです。

エスケープ処理は下記7行目のようにPOSTで送られてきた入力値をhtmlspecialcharsという関数を使用することでエスケープ処理を施し、echoで出力します。
htmlspecialchars関数については別の記事で紹介していますので、詳しくは下記をご覧ください。

PHPでのセキュリティ問題(XSSについて)

これでクロスサイトスクリプティングの対策は問題ないのですが、
この書き方では記述量が増えてしまい、コードが読みづらくなってしまうため下記のようにエスケープ関数をさらに関数化して短縮します。

これで17行目のようにhという関数を呼び出すだけでエスケープできるようになりました。
では実際にエスケープ処理ができているか確認してみましょう。

クロスサイトスクリプティング対策後

先ほどは入力値がスクリプトとして動いてしまっていましたが、今回は問題なく文字列として出力されていますね。
これでクロスサイトスクリプティングの対策が完了です。

この後に完了画面での確認メールの送信等の処理が続き、
メール内に入力値を入れる場合には確認画面の際と同じように入力値をエスケープしてから出力するという流れになります。

まとめ

ということで今回はセキュリティを考慮したお問い合わせフォームを作成しました。
いかがだったでしょうか。

今回はお問い合わせフォームを想定して作りましたが、
お問い合わせフォームに限らずユーザーから値を受け付けるフォームではどんな値が入力されるかわからないため、必ずエスケープ処理を施してから処理を行うようにしましょう。

ユーザーから受け付ける値というのはユーザーが直接入力するテキストボックスに限らず、ラジオボタンやセレクトボックスも同様です。
というのも、ラジオボタンやセレクトボックスは事前にいくつか用意した値の中からユーザーに選んでもらう形式ですが、画像のようにブラウザの検証ツールから値を自由に書き換えることができてしまうからです。

検証ツールからラジオボタンの値を書き換える

検証ツールからラジオボタンの値を書き換えたときの確認画面

そのため、ユーザー側から受け付ける値は基本的にエスケープ処理するようにしましょう。

以上、最後までご覧いただきありがとうございました~。

FOLLOW US