なぜPHPアプリにセキュリティホールが多いのか?

第8回クロスサイトスクリプティング対策の落とし

今回は熟練したWebアプリ開発者なら常識のクロスサイトスクリプティング対策の落とし穴を紹介します。

JavaScriptを排除しているつもりで排除に失敗?!

最近はSanitize(サニタイズ)という言葉の代わりにValidation(検証)という言葉をよく聞くようになったと思います。Sanitizeの意味を辞書で調べると「汚れている物をきれいにすること」とされています。この意味の通り汚れた変数をきれいにして使えば安全に利用できるとする考え方に基づくのがサニタイズ手法です。典型的な例は、⁠テキストを出力する前に"<"と">"を取り除く」方法があります。

例1 "<"と">"をereg_replaceで取り除く
$safe_text = ereg_replace($_GET['text'], '[<>]', '');

この$safe_textを

<a href="/script.php?text=<?php echo $safe_text ?>">

と出力するとXSSに脆弱になります。 $safe_textに

" onmouseover="javascript: alert('XSS')

と設定されている場合、"<"と">"を取り除いてもクロスサイトスクリプティングに脆弱となります。そこで"javascript"という文字列を排除して安全性を確保しようと試みることにします。

$safer_text = eregi_replace($safe_text, 'javascript', '');

$safer_textは、名前の通り、$safe_textより安全な文字列としてサニタイズしたつもりの文字列です。しかし、javascript文字列がなくてもブラウザがJavaScriptと認識してしまうケースは多数あります。

例2 javascript以外でJavaScriptと認識する文字列
java\0script (IE6.0)
jav&#x09;ascript (IE6.0)

このほかにも、通常JavaScriptと認識されるとは思もえないような文字列でブラウザがJavaScriptと認識してしまう例は多数あります。JavaScriptと認識するかしないかはブラウザの実装に依存しています。Windows版 Safariがベータリリース中ですが、このように新しいブラウザもリリースされています。このためサーバ側ですべてのケースに対処するのは不可能です。

さらに上記以外にも、JavaScriptを実行するのにjavascriptも<script>も必要ない場合も数多くあります。

例3 onmouseover属性でJavaScriptを実行
<b onmouseorver="alert('XSS')">XSS</b>
例4 動的にサーバ側で生成された.js(JavaScriptのみのファイル)
q = <?php echo $_GET['q'] ?>;
document.writeln(q);

※JavaScriptのみでも同様の脆弱性を発生させるコードも記述できる

このようにサニタイズにより安全性を保証したつもりでも実際には安全になっていないケースは数多くあります。

$safe_text, $safer_textのサニタイズ処理はさらに別の問題も含んでいます。ereg_replaceはバイナリセーフではないので、ヌルバイト攻撃に脆弱です。このためヌル文字(\0)以降の文字列は正規表現による置換対象となりません。"<script>alert('XSS')</script>"、"javascript"のような文字列も素通りしてしまいます。マルチバイト文字にも対応していないので、文字エンコーディングによってはereg_replaceを利用してサニタイズ処理をされていることを利用してクロスサイトスクリプティングが可能になる場合があります。

サニタイズ処理の問題

サニタイズ処理には2つの大きな問題があります。

  1. ブラックリスト方式である
  2. 不正な入力でもエラーにならない

ブラックリスト方式とは、不正な文字や文字列を定義する方式です。ブラックリスト方式が完全に機能するためには、すべての不正な入力を把握したうえで確実に検出できる手法が必要です。ブラウザの実装はブラウザごとに異なり、新しいブラウザもリリースされるので、ブラックリスト方式で安全性を確保するのは限界があることが分かります。

Webアプリケーションに限らず一般的なアプリケーションは、異常な入力を検出した場合はエラーとすべきです。サニタイズ処理でエラーを検出することも可能ですが、多くのサニタイズ処理はエラーを検出しないで不正な入力を取り除き処理を続行するコードになっています。

バリデーション処理をしよう

Webアプリケーションはサニタイズではなくバリデーション処理を行い、入力が期待している通りの形式か確認し、期待と異なる場合はエラーとしてアプリケーションの実行を停止すべきです。バリデーション処理については別のエントリで近い将来解説します。

Webアプリケーション開発フレームワークを使っているから安全!?

Webアプリケーション開発フレームワークはWebアプリの安全性を向上させるには非常に有用です。しかし、Webアプリケーション開発フレームワークを利用しているからといって、そのフレームワーク上で開発したWebアプリケーションの安全性を保証できるものではありません。どのような言語でもブラウザにテキストを直接出力する機能を持っています。ブラウザにクエリ文字列やREFERER文字列をそのまま送信するだけで、アプリケーションはクロスサイトスクリプティングに脆弱になります。

例5 フレームワークではecho/print文を防げない
<?php echo $_GET['q'] ?>

仮にすべての出力にフレームワークの機能を利用したとしても、機能の使い方が間違っていたり、利用しているJavaScriptライブラリが脆弱であった場合はクロスサイトスクリプティングに脆弱になってしまいます。残念ながらフレームワークは有用ですが万能ではありません。

まとめ

クロスサイトスクリプティングはWebサーバ側のプログラムだけでは対処できません。アプリケーション/システム全体として対処しなければなりません。システム全体にはユーザが利用するブラウザも含まれます。クロスサイトスクリプティングを完全に防ぐことは非常に難しいです。

おすすめ記事

記事・ニュース一覧