2015年5月2日土曜日

エラーメッセージによるXSSにご用心

以前の記事「PHPのdisplay_errorsが有効だとカジュアルにXSS脆弱性が入り込む」では、php.ini等でdisplay_errorsを有効にしていると、スクリプトに脆弱性がなくてもXSS(クロスサイトスクリプティング)脆弱性が入り込む可能性が高いことを指摘しました。
しかし、display_errorを無効にしていても、エラー処理がまずいと、エラー表示が原因でXSS脆弱性が入り込む場合があります。ネット上のサンプルスクリプトを見ても、潜在的にXSS脆弱性があるものが多くあります。

サンプルスクリプト

まずは、典型的な脆弱性の例をスクリプトで紹介します。PHP+PDO+PostgreSQLの組み合わせです。
<?php
try {
  $db = new PDO("pgsql:host=localhost options='--client_encoding=UTF8';dbname=test",
    DBUSER, DBPASS);
  $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 例外を有効に設定
  $ps = $db->prepare("INSERT INTO users VALUES(?, ?)");
  $ps->bindValue(1, $_GET['id'], PDO::PARAM_INT);
  $ps->bindValue(2, $_GET['name'], PDO::PARAM_STR);
  $ps->execute();
  echo '登録しました';
} catch (PDOException $e) {
  die($e->getMessage());
}
ご覧のように、PostgreSQLのデータベースに接続して、id(整数)とname(文字列)を挿入するスクリプトです。

エラーの表示例

エラー表示の例を示します。下記は、整数列であるidに「xxx」を指定した場合の画面表示です。「 invalid input syntax for integer: "xxx"」と表示されていますが、入力値が「そのまま」表示されているところに嫌な予感がしますね。


XSS

下記は、idにJavaScriptを指定した場合の画面表示です。ご覧のように、JavaScriptが起動しています。XSS脆弱性が混入してしまいました。


この際のHTMLソースは以下の通りです。
SQLSTATE[22P02]: Invalid text representation: 7 ERROR:  invalid input syntax for integer: "<script>alert(1)</script>"
エラーメッセージをHTMLエスケープしないで表示していることが原因です。

対策

本来、システム内部的なエラー内容は画面に表示すべきではありません。利用者にとっては不必要な情報であり、かつ攻撃のヒントが得られる場合があるからです。このため、エラーの詳細情報は画面表示せず、ログファイルに出力するようにします。
一方、なんからの事情があってエラー情報を画面表示する場合は、表示の前にHTMLエスケープすべきです。
例: echo htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8');

まとめ

エラーメッセージに起因するXSSについて説明しました。
Google検索で「PDOException getMessage」で検索すると、エラー詳細をHTMLエスケープしないで表示しているサンプルが大半です。学習目的あるいはデバッグ用という意図かもしれませんが、サンプルには明示されていないため、初学者はそれが「正しい書き方」と思うのではないでしょうか。
そもそもエラー詳細を画面表示しないことが原則ですが、説明等の目的でエラー内容を表示する場合は、常に正しいスクリプトを示すという意味からHTMLエスケープを忘れないようにいたしましょう。


【HASHコンサルティング広告】
HASHコンサルティング株式会社は、セキュリティエンジニアを募集しています。
興味のある方は、twitterfacebookのメッセージ、あるいは問い合わせページからお問い合わせください。


0 件のコメント:

コメントを投稿

フォロワー