しかし、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コンサルティング株式会社は、セキュリティエンジニアを募集しています。
興味のある方は、twitterやfacebookのメッセージ、あるいは問い合わせページからお問い合わせください。
0 件のコメント:
コメントを投稿