XSSの脆弱性を限りなくなくす方法
XSSがはやっているので便乗しておきます。
私がよく使う方法なんですが、この方法を利用するとXSSの脆弱性を限りなくなくすことが出来ます。
対応方法は、PHPファイルの最初に以下のコードを挿入するだけ。
foreach($_GET as $key => $value){
$_GET[$key] = htmlspecialchars(htmlspecialchars_decode($value,ENT_QUOTES),ENT_QUOTES);
}
foreach($_POST as $key => $value){
$_POST[$key] = htmlspecialchars(htmlspecialchars_decode($value,ENT_QUOTES),ENT_QUOTES);
}
これで自動的にエスケープの処理を行ってくれます。
通常のXSS対策がエスケープしたくない場所以外はhtmlspecialcharsを利用してでエスケープを行うのに対して、このコードを入れることによりエスケープしたくない場所にhtmlspecialchars_decodeを利用するといった全く逆のアプローチになります。
これでうっかりXSSスクリプティング対策忘れというのを防ぐことができます。
htmlspecialchars_decodeはPHP5から利用できる関数ですので、PHP4ではhtml_entity_decodeを利用すること大体同じような効果が得られます。
サンプルコードで一度デコードを行ってからエスケープを行っているのは実体参照化された文字列に更に実体参照化していくと「&」とえらい事になるからです。
GETやPOSTで受け取る値の性質が変わるので、すべてのプログラムで冒頭に入れれば動作するという魔法のコードではないですが、導入すれば楽してXSS対策ができるかなと思います。
また、すべてのXSSの脆弱性に対応できるわけでもないのであしからず。
追記
いくつかの反応をみていると入力時ではなく、サニタイズせず出力時にエスケーブすべきとの反応が見受けられます。それに関しては全くその通りで否定はしないんだけども、XSS脆弱性の大半が「対策漏れ」から来るものだと思っていて、「対策漏れ」に関してはXSS対策の正しい知識があるかどうかとは別の次元の話だとおもう(だから一流のプログラマが参加しているようなシステムでもXSS脆弱性が発生してるんだよね)。あくまで「対策漏れ」をなくす一つのアプローチだと思っていただけたらよいかと。
ベストの対策はアプリの性質に合わせたエスケープなんだけども、これって完全になくすにはかなりの几帳面さが必要になるんじゃないかなと思います。(規模が大きくなればなるほど)
また、出力時に、エスケープするのはフレームワークなり何なり利用すればいいんだけども、それはシステムの出力アプローチによって色々変わるのでケースバーイケースで対応していく必要があるのではないかと。
当然「限りなくなくす」なんて書いている通り「完全になくす」方法ではないです。script要素内やstyle要素内、イベントハンドラ内で利用したらXSS脆弱性になるし、$_REQUESTを利用している場合もエスケープされない、また途中のコードによってはアンエスケープされたものを出力してしまうなど、完全になくそうと思えばやっぱり正しい知識が必要なるります。
別に出力時のエスケープと併用しても問題ないかなと思いますし。
さらに追記
「<」も「<」も「<」として表示されるので入力データを生で利用したい場合などには向きません。
生データを利用したい場合は$_REQUESTというのもありだけど、「<」と「<」を使い分けるような処理が必要な場合には、めんどくさくなるので私も使いません。
なんども書きますが「魔法のコード」ではありませんので。
さらにさらに追記
私が伝えたいことが全く伝わらないエントリーのようなので、全部delしました。
有効な局面でのみ利用すれば良いだけの話なんですけどね。。。
関連エントリー
WEBデザイナーの為のXSS(クロスサイトスクリプティング)入門
PHPサイバーテロの技法―攻撃と防御の実際
re:キケンなSQLインジェクション
SQLインジェクションについて
絶対に公開してはいけないPHPプログラミング