2013年4月4日木曜日

PHPのdisplay_errorsが有効だとカジュアルにXSS脆弱性が入り込む

先に、「CVE-2008-5814を巡る冒険」にて、CVE-2008-5814脆弱性があるとdisplay_errorsがOnの環境下でXSS脆弱性となる場合があることを説明しました。しかし、display_errorsがOnの環境下ではCVE-2008-5814脆弱性がなくても、XSS脆弱性となる場合がしばしばあります。
これは、display_errorsによるエラーメッセージ表示がHTMLエスケープされていないことが原因です。簡単なサンプルを以下に示します。
<?php
  ini_set('display_errors', 1); // display_errorsを有効にする
  $a = array();                 // 配列の生成
  $index = $_GET['x'];          // 配列のインデックスを得る
  $b = $a[$index];              // 配列の要素にアクセス
このスクリプトに、x=<script>alert(1)</script> というクエリ文字列をつけて呼び出すと下記の表示になります(error_reporting設定でE_NOTICEが有効になっている場合です。E_NOTICEはphp.ini上の設定がない場合は無効ですが、多くのphp.ini設定では有効となっています)。


この際のHTMLソースは以下の通りです。
Notice: Undefined index: <script>alert(1)</script> in /var/www/de.php on line 5
Undefined indexとして、外部から与えたパラメータが「そのまま」(HTMLエスケープされずに)出力されています。 

PHPの脆弱性なのか?

これはPHPの脆弱性なのでしょうか。CVE-2008-5814が脆弱性なのであれば、こちらも脆弱性と見るべきだと思います。そうしないと辻褄があいません。 
一方、display_errorsはデバッグ用の設定なのだから、本番環境に適用する方が悪いという意見もあるでしょう。この立場に立てば、上記はPHPの脆弱性ではないという見方もあり得ます。その場合は、CVE-2008-5814も(実は)脆弱性ではないとしなければなりませんが…
しかし、仮にPHPの脆弱性でないとしても、display_errorsによるエラー表示はHTMLエスケープすべきだと考えます。そうしないと、正しい表示にならないからです。
先の例では、Undefined indexとして表示すべき内容は、<script>alert(1)</script> という文字列であって、JavaScriptの実行ではありません。display_errorsによるエラー表示はHTMLエスケープしなければ、正しい表示にならない場合があります。すなわち、HTMLのエスケープ漏れはPHPの仕様上の不具合と言えます。そして、仕様上の不具合(バグ)が環境依存とはいえ脆弱性になり得るとすれば、結局PHP自体の脆弱性と言わざるを得ないと徳丸は考えます。

プログラミングでなんとかならないのか?

配列の未定義のキーによるアクセスを防ぐこと自体は難しくありません。たとえば、array_key_exists関数を使って、キーの存在を事前に確認する方法。
$b = array_key_exists($index, $a) ? $a[$index] : null;
同じくisset()を使う方法。
$b = isset($a[$index]) ? $a[$index] : null;
エラー制御演算子(@)を使ってエラー表示を抑止する方法。
$b = @$a[$index];
すべての箇所で上記を徹底すれば、Undefined indexの警告によるXSSは防げるはずです。しかし、その他のエラー・警告も含め、すべてを漏れなくなくすことは難しいため、display_errorsはやはり無効にすべきです。

display_errorsは本番環境ではOffにしよう

従来から、セキュリティ上の理由からデバッグ目的のエラー表示は抑止すべしと言われています。その主な理由は下記の通りです。
  • デバッグ用のエラーメッセージが攻撃者にとってヒントになる場合がある
  • エラーメッセージを通じて情報漏洩させる手口がある(→参考
  • そもそもユーザフレンドリでないし、みっともない(セキュリティ上の理由ではない)
加えて、クロスサイトスクリプティングという具体的な脅威になり得ると言うことです。一般論としても、エラー画面にはクロスサイトスクリプティング脆弱性が生じやすいという経験則があります。よって以下にお気をつけ下さい。
  • display_errorsなどデバッグ用のエラー表示は本番リリース前にオフにする
  • エラー表示は利用者向けに必要最低限の表示にとどめ、問題解決用の情報はログとして出力する
  • エラーメッセージにはクロスサイトスクリプティングが入りやすいので注意(と言っても、特別なことをするわけではなく、エラー表示だからと言って手を抜かずにHTMLエスケープしろということです)

0 件のコメント:

コメントを投稿

フォロワー