HTML文字のエスケープ
そふぃのPHP入門 >> PHP実践リファレンス >> フォーム処理 >> HTML文字のエスケープ

HTML文字のエスケープ

エスケープが必要な訳

掲示板などに代表されるように、「フォームから取得したデータを表示する」というスクリプトは非常に多いですが、フォームからのデータを表示する場合には注意が必要です。フォームからのデータは、ユーザが入力するデータのため、どのような値が代入されているか特定できません。例えば<h1>などのHTMLタグをフォームから送信された場合にはどうなるでしょうか。

タグの効果までしっかり反映されて、<h1>タグ以降の文字がしっかり大きくなります。これがHTMLタグなら笑って済ませられるかもしれませんが、スクリプトを埋め込まれたりするととっても危険です。ユーザが任意のスクリプトを実行できてしまう事になりますので、場合によってはcookieを盗まれたり、認証をパスされたりとおっかない事が起こります。

良く分からないと思うので、スクリプトと画像でごく簡単に説明します。以下は簡単なフォーム処理スクリプトです。

<html>
<head>
</head>
<body>
<form action="" method="post">
  <input type="text" name="textbox" value="" />
  <input type="submit" value="送信" />
</form>
入力文字:
  1. <?php
  2. print $_POST["textbox"];
  3. ?>
</body>
</html>

このスクリプトを実行すると、

クロスサイトスクリプティング検証:フォーム画面

上記のようなフォームが出来上がります。

HTMLタグを挿入してみる

これに<h1>タグを挿入すると・・・・

クロスサイトスクリプティング検証:タグ入力画面クロスサイトスクリプティング検証:入力処理後画面

のように思いっきり<h1>が反映されて表示されます。掲示板などでこれをやられるとサイトのデザインが意図した通りにいきませんし、終了タグの</h1>を抜いて送信された場合には、それ以降に全て(といっても次に</h1>が出てくるまで)<h1>が適用されてしまう・・・なんて事も起こりえます。

スクリプトを挿入してみる

スクリプトを挿入した場合にはもっと厄介です。

クロスサイトスクリプティング検証:スクリプト入力画面クロスサイトスクリプティング検証:入力処理後アラート出現画面

今回は大したスクリプトを挿入してませんが、それでも掲示板で使われれば、ページを開くたびにダイアログが出てくるなんていうウザイページが自分の意図に反して出来上がってしまいます。

この手の攻撃をクロスサイトスクリプティングと言うのですが、クロスサイトスクリプティングについてここで細かく説明していくと肝心のエスケープ処理に入る前に何ページか読んでもらわないとならなくなる為w、肝心のエスケープ処理の方法に入りたいと思います。ネット上にはクロスサイトスクリプティングについて詳しく書かれたドキュメントがたくさん存在しますので、ぜひ一度検索してみて下さい。

HTML文字のエスケープ処理

さて、クロスサイトスクリプティングを防止するだけなら、タグの使用自体を禁止してスクリプト側ではタグを取り除く、って方法がありますが、これだとHTMLやPHPを題材にした掲示板には向きませんし、制限事項が増えてユーザの使い勝手が悪くなりそうです。

クロスサイトスクリプティングを防止して、なおかつタグの入力もできるようにするためにはエスケープ処理を行います。HTMLの記述方法の1つに、「<」、「>」自体を出力したい場合には「&lt;」、「&gt;」で記述する、という規則があります。これを利用すると、タグなんかもちゃんとブラウザ上で表示できるようになります。

&lt;br&gt;

出力結果

<br>

エスケープ処理とはあるデータ形式中で特別な意味を持つ記号や文字などを一定のルールに従って変換する事をいいます。あんまり難しく考えなくても、今回は<&lt;に、>&gt;に変換したいだけです。PHPでこれをするにはhtmlspecialchars()を使うだけです。

参考関数

書式

  • string htmlspecialchars( string string [, int quote_style [, string charset ]] )

よく分からないかもしれませんが、htmlspecialchars()は、「<」を「&lt;」に、「>」を「&gt;」に変換してくれるというそのものずばりの関数です。他にも「&」を「&amp;」に変換してくれます。第3引数までありますが、通常使用するには第1引数だけ指定すれば十分です。この第1引数に変換したい文字列を指定します。補足までに、第2引数は"(ダブルクォート)と'(シングルクォート)を変換するかどうか、第3引数は変換に使用する文字コードの指定です。興味のある方は関数のページを参照してもらうことにして、早速スクリプトです。

<form action="<?= $_SERVER['PHP_SELF']; ?>" method="post">
  <input type="text" name="textbox" value="" />
  <input type="submit" value="送信" />
</form>
入力文字:
  1. <?php
  2. print htmlspecialchars( $_POST["textbox"] );
  3. ?>

出力結果

入力文字:

前のスクリプトとの違いは2つだけで、print()文の出力に今まで解説してきたhtmlspecialchars()を使用していることと、<form>タグのaction属性に$_SERVER['PHP_SELF'];が入ってることだけです。

action属性の$_SERVER['PHP_SELF'];の方は、「現在のページ」を示すサーバ変数です。これに関してはHTMLの記述ルール上、<form>タグのaction属性が省略不可となってるので指定していますが、空のままだと「現在のページ」と認識するブラウザが多いようです。空のままでも問題なく動きますが、HTMLの記述ルールには従った方がいいと思いますので挿入しています。

$_SERVER['PHP_SELF'];などのサーバ変数に関しては、以下のページを参照して下さい。

参考 サーバ変数

ちょっと話がそれましたが、肝心のhtmlspecialchars()には$_POST['textbox']を引数に指定して、タグなどの変換をしてもらってから表示してます。試してみると分かりますが、HTMLタグを入力して送信しても&lt;&gt;に変換してから出力するので、HTMLタグはちゃんと表示されるわスクリプトは無害になるわでめでたしめでたしです。掲示板などユーザからの入力を表示することが必要となるスクリプトでは基本の処理ですのでしっかり覚えておいて下さい。

これでようやく公開できるようになるかと思いきや、他にもマジッククォートの処理なんて聞きなれないものの処理もした方がいいです。マジッククォートについては次のページで紹介しますので、まだあんのかよ・・・と思わずにお付き合い下さい。