PHP 5 フォームの検証

❮ 前章へ 次章へ ❯

この章と次の章では、PHPを使用したフォームデータの検証方法を説明します。


PHP フォーム検証

PHPのフォームを処理する際は、セキュリティを考慮してください!

このページでは、セキュリティを考慮したPHPのフォーム処理方法を説明します。 フォームデータの適切な検証は、フォームをハッカーやスパマーから守るために重要です!

この章で取扱うHTMLフォームには、さまざまな入力フィールドがあります: 必須およびオプションのテキストフィールド、ラジオボタン、送信ボタンなど:

フォームの検証規則は次のとおりです:

フィールド 検証の規定
名前 必須。+ 文字と空白のみを含まなければならない
E-mail 必須。+ 妥当なメールアドレス(@ と .)を含まなければならない
Website 任意。存在する場合は、妥当な URL を含まなければならない
Comment 任意。複数行入力フィールド(テキストエリア)
Gender 必須。1つを選択しなければならない

まず、フォームのプレーンHTMLコードを見てみましょう:


テキストフィールド

name、email、website フィールドはテキスト入力要素で、comment フィールドはテキストエリアです。 HTMLコードは次の通りです:

Name: <input type="text" name="name">
E-mail: <input type="text" name="email">
Website: <input type="text" name="website">
Comment: <textarea name="comment" rows="5" cols="40"></textarea>

ラジオボタン

genderフィールドはラジオボタンで、HTMLコードは次の通りです:

Gender:
<input type="radio" name="gender" value="female">Female
<input type="radio" name="gender" value="male">Male

フォーム要素

フォームのHTMLコードは次の通りです:

<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">

フォームを送信すると、フォームデータは method="post" で送信されます。

$_SERVER["PHP_SELF"] 変数とは何ですか?

$_SERVER["PHP_SELF"] は、現在実行中のスクリプトのファイル名を返すスーパーグローバル変数です。

したがって、$_SERVER["PHP_SELF"]は、別のページにジャンプするのではなく、送信されたフォームデータをページ自体に送信します。 これにより、フォームと同じページにエラーメッセージが表示されます。

htmlspecialchars() 関数とは何ですか?

htmlspecialchars() 関数は、特殊文字をHTMLエンティティに変換します。これは、< や > のようなHTML文字を、&lt; や &gt; 置換する することを意味します。 これにより、フォームにHTMLまたはJavascriptコードを挿入した攻撃(クロスサイトスクリプティング攻撃)を防御します。


"> ユーザーが「http://www.example.com/test_form.php」のようなアドレスバーに通常のURLを入力すると、上記のコードは次のように変換されます。

PHPフォームセキュリティに関する大きな問題点

$_SERVER["PHP_SELF"] 変数はハッカーによって使われます!

ページでPHP_SELFを使用している場合、ユーザはスラッシュ(/)を入力でき、 且ついくつかのクロスサイトスクリプティング(XSS)コマンドを実行することができます。

クロスサイトスクリプティング(XSS)は、Webアプリケーションで一般的に見られる種類のコンピュータセキュリティの脆弱性です。 XSSを使用すると、攻撃者は他のユーザが閲覧したWebページにクライアント・サイドス・クリプトを挿入することができます。

"test_form.php" という名前のページに次のフォームがあったとします:

<form method="post" action="<?php echo $_SERVER["PHP_SELF"];?>">

ユーザが、アドレスバーに"http://www.example.com/test_form.php"のような通常のURLを入力すると、上のコードは次のように変換されます:

<form method="post" action="test_form.php">

ここまでは順調です。So far, so good.

しかし、ユーザがアドレスバーに次の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>

このコードは、スクリプトタグと警告コマンドを追加します。このページがロードされると、 JavaScriptコードが実行されます(ユーザに警告ボックスを表示します) これは、PHP_SELF変数がどのように悪用されるかという単純で無害な例です。

<script> タグ内には、あらゆるJavaScriptコードを追加できることに注意してください! ハッカーは、ユーザを別のサーバのファイルにリダイレクトすることができます。そのファイルには、グローバル変数を変更したり、 フォームを別のアドレスに送信してユーザ・データを保存するなどの悪意のあるコードを持つことが可能です。


$_SERVER["PHP_SELF"]エクスプロイト(*)を回避するには?

$_SERVER["PHP_SELF"]エクスプロイトは、htmlspecialchars()関数を使用することで回避できます。

フォームのコードは次の通りです:

<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">

htmlspecialchars()関数は、特殊文字をHTMLエンティティに変換します。ユーザがPHP_SELF変数を利用すると、次のような結果になります:

<form method="post" action="test_form.php/&quot;&gt;&lt;script&gt;alert('hacked')&lt;/script&gt;">

エクスプロイトの試みは失敗し、害はありません!The exploit attempt fails, and no harm is done!

(訳注)*:エクスプロイトとは、スクリプト、あるいはプログラムの1つで、コンピュータ関連においてソフトウェアやハードウェアの脆弱性を利用し、 悪意を持った行為のために書かれたものである。


PHPによるフォームデータの検証

まずやるべきことは、すべての変数をPHPのhtmlspecialchars()関数に渡すことです。

htmlspecialchars() 関数を使用するときに;ユーザがテキストフィールドに次の項目を送信しようとすると:

<script>location.href('http://www.hacked.com')</script>

- 次のようにHTMLエスケープコードとして保存されるため、これは実行されません:

&lt;script&gt;location.href('http://www.hacked.com')&lt;/script&gt;

ページやメールの中に表示しても、このコードは安全です。

ユーザがフォームを送信した時に、さらに2つのことを行います:

  1. ユーザ入力データから不要な文字(余分なスペース、タブ、改行)を取り除きます(PHPの trim() 関数を使用する)
  2. ユーザ入力データからバックスラッシュ(\)を削除します(PHPの stripslashes() 関数を使用する)

次のステップは、すべてのチェックを行う関数を作成することです(同じコードを何度も繰り返し書くよりもずっと便利です)。

関数名をtest_input()とします。

各$_POST変数をtest_input()関数でチェックすると、スクリプトは次のようになります:

<?php
// define variables and set to empty values
$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);
  return $data;
}
?>
例の実行 »

スクリプトの開始時に、$_SERVER["REQUEST_METHOD"]を使用してフォームが送信されたかどうかを確認していることに注意してください。 REQUEST_METHODがPOSTの場合は、フォームは送信されているので、検証する必要があります。 送信されていない場合は、検証をスキップして空白のフォームを表示します。

しかし、上の例では、すべての入力フィールドはオプションです。ユーザがデータを入力しなくてもスクリプトは正常に動作します。

次のステップでは、必須な入力フィールドを作成し、必要に応じてエラーメッセージを作成します。


❮ 前章へ 次章へ ❯