PHP フォームバリデーション
1. PHP フォームバリデーションの重要性
PHP でフォームを処理する際は、常に セキュリティ を最優先に考えてください。
これからのセクションでは、セキュリティを意識した PHP フォームの処理方法について解説します。ハッカーやスパマーからフォームを守るためには、フォームデータに対して適切なバリデーション(入力検証)を行うことが極めて重要です。
本章で扱う HTML フォームには、必須入力項目、任意入力項目、ラジオボタン、送信ボタンなど、さまざまな入力フィールドが含まれています。
1.1 バリデーションルール
このフォームに適用するバリデーションルールは以下の通りです。
| フィールド | バリデーションルール |
|---|---|
| 名前 (Name) | 必須。文字と空白のみ許可。 |
| メールアドレス (E-mail) | 必須。有効なメール形式であること(@ と . を含む)。 |
| ウェブサイト (Website) | 任意。入力がある場合は有効な URL であること。 |
| コメント (Comment) | 任意。複数行入力フィールド(textarea)。 |
| 性別 (Gender) | 必須。いずれか一つを選択。 |
2. フォームの構成要素
まず、フォームに使用する基本的な HTML コードを確認しましょう。
2.1 テキストフィールド
名前、メール、ウェブサイトの各フィールドはテキスト入力要素であり、コメントフィールドは textarea です。
HTML コード:
名前: <input type="text" name="name">
メール: <input type="text" name="email">
ウェブサイト: <input type="text" name="website">
コメント: <textarea name="comment" rows="5" cols="40"></textarea>2.2 ラジオボタン
性別フィールドはラジオボタンを使用します。
HTML コード:
性別:
<input type="radio" name="gender" value="female">女性
<input type="radio" name="gender" value="male">男性
<input type="radio" name="gender" value="other">その他3. フォーム要素とアクションの設定
フォーム自体の HTML コードは以下のようになります。
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">フォームが送信されると、データは method="post" で送られます。ここで重要な2つの要素について説明します。
3.1 $_SERVER["PHP_SELF"] 変数とは
$_SERVER["PHP_SELF"] は、現在実行中のスクリプトのファイル名を返すスーパーグローバル変数です。
これを使用することで、送信されたフォームデータを別のページに飛ばすのではなく、同じページ(自分自身)に送ることができます。これにより、ユーザーはフォームと同じページ上でエラーメッセージを確認できるようになります。
3.2 htmlspecialchars() 関数とは
htmlspecialchars() 関数は、特殊文字を HTML エンティティに変換します。つまり、< や > といった HTML 文字を < や > に置き換えます。
これにより、フォーム内に HTML や JavaScript コードを注入して悪用する攻撃(クロスサイトスクリプティング / XSS 攻撃)を防ぐことができます。
4. セキュリティ警告:$_SERVER["PHP_SELF"] の脆弱性
$_SERVER["PHP_SELF"] 変数は、適切に扱わないとハッカーに悪用される恐れがあります。
もしページ内で PHP_SELF がそのまま使用されていると、ユーザーが URL の末尾にスラッシュ / に続けて XSS コマンドを入力し、実行させることが可能になります。
XSS(クロスサイトスクリプティング) とは、Web アプリケーションに見られるセキュリティ脆弱性の一種です。攻撃者はこれを利用して、他のユーザーが閲覧する Web ページにクライアントサイドのスクリプトを注入します。
例えば、"test_form.php" というページに以下のフォームがあると仮定します。
<form method="post" action="<?php echo $_SERVER["PHP_SELF"];?>">通常の URL http://www.example.com/test_form.php でアクセスした場合、コードは以下のようにレンダリングされます。
<form method="post" action="test_form.php">しかし、悪意のあるユーザーが以下のような URL をアドレスバーに入力した場合はどうなるでしょうか。
http://www.example.com/test_form.php/%22%3E%3Cscript%3Ealert('hacked')%3C/script%3E
この場合、コードは以下のように変換されてしまいます。
<form method="post" action="test_form.php/"><script>alert('hacked')</script>このコードにより script タグと alert コマンドが追加され、ページが読み込まれると JavaScript が実行されます(アラートボックスが表示されます)。これは PHP_SELF が悪用される単純な例に過ぎません。
<script> タグ内には、あらゆる JavaScript コードを追加できるという点に注意してください。ハッカーはユーザーを別のサーバー上のファイルにリダイレクトさせたり、そのファイルからグローバル変数を書き換えたり、ユーザーデータを保存するためにフォームを別の宛先に送信させたりすることが可能です。
4.1 $_SERVER["PHP_SELF"] の悪用を回避する方法
これらのエクスプロイト(脆弱性攻撃)は、前述の htmlspecialchars() 関数を使用することで回避できます。
推奨されるコード:
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">htmlspecialchars() が特殊文字をエンティティに変換するため、もしユーザーが PHP_SELF を悪用しようとしても、出力は以下のようになります。
<form method="post" action="test_form.php/"><script>alert('hacked')</script>">攻撃の試みは無効化され、実害は及びません。
5. PHP によるデータバリデーションの実装
最初のステップとして、すべての変数を PHP の htmlspecialchars() 関数に通します。
例えば、ユーザーがテキストフィールドに以下の内容を送信しようとした場合:<script>location.href('http://www.hacked.com')</script>
これは実行されません。なぜなら、以下のように HTML エスケープされた状態で保存されるからです。<script>location.href('http://www.hacked.com')</script>
これにより、ページに表示したりメールに含めたりしても安全な状態になります。
さらに、フォーム送信時に以下の2つの処理も追加で行います。
- 不要な文字の除去:
trim()関数を使用して、入力データから余分なスペース、タブ、改行を削除します。 - バックスラッシュの削除:
stripslashes()関数を使用して、入力データからバックスラッシュ \ を削除します。
5.1 test_input() 関数の作成
これらのチェックを毎回記述するのは非効率なため、すべての処理をまとめた関数を作成します。ここでは関数名を test_input() とします。
この関数を使用して各 $_POST 変数をチェックするスクリプトは以下の通りです。
実装例:
<?php
// 変数を定義し、空文字で初期化
$name = $email = $gender = $comment = $website = "";
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$name = test_input($_POST["name"]);
$email = test_input($_POST["email"]);
$website = test_input($_POST["website"]);
$comment = test_input($_POST["comment"]);
$gender = test_input($_POST["gender"]);
}
/**
* 入力データをサニタイズする共通関数
*/
function test_input($data) {
$data = trim($data); // 前後の空白を削除
$data = stripslashes($data); // バックスラッシュを削除
$data = htmlspecialchars($data); // HTMLエンティティに変換
return $data;
}
?>スクリプトの冒頭で $_SERVER["REQUEST_METHOD"] を使用して、フォームが送信されたかどうかを確認している点に注目してください。REQUEST_METHOD が POST であればフォームが送信されたと判断し、バリデーションを実行します。送信されていない場合はバリデーションをスキップし、空のフォームを表示します。
なお、上記の例ではすべての入力フィールドが任意(Optional)となっているため、ユーザーがデータを入力しなくてもスクリプトは正常に動作します。次のステップでは、必須項目のバリデーションについて学んでいきましょう。