ユーザの入力をフォームで受け付けWEBページに出力する処理を含んだプログラムでは、入力値のサニタイジング(無害化)が必要です。WEBブラウザは表示内容にhtmlタグが含まれているとこれを自動的に解釈して反映してしまうため、悪意あるユーザがタグを混入させた入力を行えば、表示出力段階で設計者の想定外の処理が行われてしまうからです。
実例を見てみましょう。たとえば以下のような簡単なプログラムがあったとします。
<html>
<head>
<title>sample.php</title>
</head>
<body>
<?php
echo $_POST["userin"];
?>
フォームへの入力値を表示する
<form action="sample.php" method="post">
<input type="text" name="userin"></input>
<input type="submit" value="送信"></input>
</form>
</body>
</html> |
<html>
<head>
<title>sample.php</title>
</head>
<body>
<?php
echo $_POST["userin"];
?>
フォームへの入力値を表示する
<form action="sample.php" method="post">
<input type="text" name="userin"></input>
<input type="submit" value="送信"></input>
</form>
</body>
</html>
このプログラムのユーザ入力に、<h1>このページの内容は嘘八百である</h1>というタグ付きテキストを渡してみます。するとh1タグが解釈され、目立って大きなテキストとして表示されてしまいます。たとえば掲示板プログラムなど、ユーザ入力が残り続けるページの場合にはこの「このページの内容は嘘八百である」という文言が残り続け、h1タグが付いているため検索エンジンにもこれがページの主要内容と誤解されてしまいます。さらに掲示板の背景色と同じ文字色をタグで指定すれば、管理者にも容易に気付かれずこの文言が残り続けることになります。
また、タグが解釈されてしまうということはscriptタグに挟んだ任意のスクリプトも実行できてしまうということです。ユーザの情報をクッキーに保存しているサイトで、<script>alert(document.cookie);</script>と入力すれば、scriptタグ中のjavascriptが処理され、クッキーに保存されたユーザ情報にアクセスできてしまいます。
この脆弱性と、アドレスにフォームへの入力内容を付加できるという特性を利用して行われるのがXSS(クロスサイトスクリプティング)です。この場合攻撃者(Aとします)は攻撃対象サイト(B)のアドレスにフォーム入力内容を加えたリンクを、悪意の無いユーザ(C)に踏ませます。クッキーに格納されたユーザ(C)の情報はスクリプトにより攻撃者(A)に取得され、たとえばそれがパスワードであった場合には不正アクセスが可能になってしまいます。さらにクッキーに保存された情報の種類によっては、もっと深刻な個人情報の漏洩にもなり得ます。
このような攻撃への対策として行われるのがサニタイジングです。htmlタグを示す<や>といった文字をエスケープして他の文字列を充てるという処理で、PHPにはそれを行う関数が幾つか存在します。以下それらの関数個別の説明を行います。
strip_tags関数
この関数はその名の通り、htmlとPHPのタグを文字列から取り除きます。また2番目の引数として特定のタグを与えることで、そのタグは取り除かないといった指定もできます。一見便利そうですが、タグであるとの判定が<と>に囲まれているということなので、ユーザ入力として閉じてないタグ(例:<script)を与えられると、遥か先に存在する>を探し出してそこまでの文字列を全て取り除いてしまうという可能性があり諸刃の剣です。
addslashes関数
この関数がエスケープするのはタグを構成する文字ではなく、シングルクォート、ダブルクォート、スラッシュといったデータベース操作のSQL文を構成する要素です。これはSQLインジェクションという攻撃への対策であり、このエントリの内容からは外れるのですが、ここで言及するのはこの機能をデフォルトでオンにしているレンタルサーバが多いからです。
正確にはPHP設定のmagic_quotes_gpcという項目名のもので、これがonになっていると自動的にフォーム入力値にaddslashes関数が実行されるというものです。先程のフォーム入力表示プログラムにエスケープ対象になる文字列を入力して、バックスラッシュや¥マークが付加されて表示される場合はこれが有効になっています。ある意味この自動エスケープも入力内容の予期せぬ改変を引き起こすと言えなくもなく、またSQLインジェクションへの対策という点から見てもこの機能は不完全ですので、PHPの最新ヴァージョンでmagic_quote_gpcが廃止されるなどの動きもあるようです。この辺りの話はまたSQLインジェクションについてのエントリを立てて説明します。
htmlspecialchars関数
この関数は、htmlタグを構成する<と>、&、設定によってはシングルクォートとダブルクォート、以上の5種類に対しエスケープを行ってくれる関数です。&に何故エスケープが必要かというと、この文字はエスケープ変換後の文字列の先頭に現れエスケープの表明になるからです。たとえば<をエスケープすると<という文字列になります。シングルクォート、ダブルクォートについても、CSSでの値指定で使われる文字で、これを利用した攻撃方法が存在するのでエスケープの必要があります。デフォルトではダブルクォートのみエスケープという指定になっているので、この関数を利用する際には引数を与えシングルクォートのエスケープも有効にしなければなりません。以下は書式です。
htmlspecialchars(引数1,引数2,引数3);
/*
引数1:変換対象文字列
引数2:(省略可)クォートの扱い。0〜3の整数値または定数で指定。
定数ENT_QUOTESを与えると両方変換する。
引数3:(省略可)文字コード。UTF-8など明示的に指定しておいた方が良い。
*/ |
htmlspecialchars(引数1,引数2,引数3);
/*
引数1:変換対象文字列
引数2:(省略可)クォートの扱い。0〜3の整数値または定数で指定。
定数ENT_QUOTESを与えると両方変換する。
引数3:(省略可)文字コード。UTF-8など明示的に指定しておいた方が良い。
*/
この関数を常に使うのが有効な対策です。
htmlentities関数
htmlspecialchars関数と同じく文字列を<のようにエスケープしてくれるのですが、対象文字がエスケープ可能な全ての文字にわたります。ウムラウト付き文字やギリシャ文字、記号類が主な対象です。全てのリストは、htmlの特殊文字などで検索して調べて下さい。
この関数をhtmlspecialchars関数の代わりに使うこともできます。ただやはりクォートのエスケープのデフォルト値はダブルクォートのみなので、第二引数にENT_QUOTESを与えて下さい。
ユーザからの入力を表示するプログラムにサニタイジングが必要ということは、前回作成したようなファイルアップロードを受け付けるプログラムでも適切なエスケープが必要になります。ファイルから読み込んで表示する部分にエスケープするのは勿論ですが、$_FILES変数の$_FILES[][‘type’]、$_FILES[][‘name’]などについても、ユーザが任意の値を設定できるため、エスケープするべきです。
以上がPHPでのサニタイジングです。サニタイジング以外にも、ファイル構成や入力チェックなどでセキュリティを上げることが可能ですので、その方面での対策と常にセットで考えておきましょう。