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

第7回いまさらながらクロスサイトスクリプティングの基礎の基礎

今回はWebアプリケーションを作ったことがない方でも分かるようクロスサイトスクリプティング脆弱性を解説します。

クロスサイトスクリプティングとは?

初めてクロスサイトスクリプティングと聞いて、どのような問題なのかすぐに理解できる人はいないと思います。サイトAに記述されたJavaScriptプログラムがサイトB上で実行されるために発生することが問題とされたので、⁠サイト間をまたがるスクリプトの実行」問題として、クロスサイトスクリプティング(XSS)と名前が付けられました。この命名では直感的に分かりづらい、サイト間にまたがらずHTMLメールなどにJavaScriptを挿入する攻撃でも同じ効果が得られることから、⁠JavaScriptインジェクション」とも呼ばれるようになっています。

図1 簡単なクロスサイトスクリプティング
図1 簡単なクロスサイトスクリプティング
例1 簡単な直接攻撃
掲示板サイトに投稿されたデータをエスケープ処理なしに出力し、ユーザが送信したJavaScriptを含む投稿データがブラウザに送信され掲示板を見たユーザのセッションIDが盗まれた。

Webアプリケーションは、作り方を間違えると「インジェクション」⁠コードや特殊文字などの挿入)により、セキュリティ上重大な問題を簡単に作れてしまいます。クロスサイトスクリプティングはインジェクション攻撃の中でも最も防御が複雑で難しいセキュリティ上の問題です。

なぜクロスサイトスクリプティングは危険な脆弱性なのか?

Webアプリケーションプログラミングに慣れていない方は、インジェクト(挿入)されたJavaScriptコードが実行されて何が困るのか解らないかもしれません。JavaScriptはブラウザに保存されたクッキーにアクセスしたり、ブラウザに出力されるページを変更できます。⁠任意のJavaScriptコードを挿入できる」ことは「クッキーの取得」⁠ページの内容を書き換え」が可能になることを意味します。

クッキーはHTTPセッション管理に利用されるセッションIDに利用されます。⁠クッキーの取得」「セッションIDの取得」が可能であることを意味します。つまり、ログイン済みの第三者のアカウントを不正に利用可能になります。詳しい説明は省略しますが、匿名性を維持しつつセッションIDの収集をするは非常に簡単です。

例えば、ログインページがクロスサイトスクリプティングに脆弱であった場合は、ユーザIDとパスワードを簡単に盗み取れます。JavaScriptはドキュメントの任意ノード(構成要素)を書き換えることができます。ログイン名、パスワードを記述したフォームを書き換えて、攻撃者のサーバに送信するページに置き換えられます。有名なサイトではあり得ないことのように思いますが、PayPalのログインページはクロスサイトスクリプティングに脆弱でした。

なぜクロスサイトスクリプティングは無くならないのか?

この連載ではSQLインジェクションは簡単に防げると書きました。SQLインジェクションはクエリ実行時にスドアドプロシージャを利用するか、すべての変数を適切な方法でエスケープするだけで完全に防げます[1]⁠。しかし、クロスサイトスクリプティング脆弱性は簡単には防げません。

クロスサイトスクリプティングが無くならない理由

  1. すべての出力をエスケープできない
  2. 出力する場所によって適切なエスケープ方法が異なる
  3. どの変数がユーザからの入力を含んでいるか分かりづらい
  4. クライアント側(JavaScript)の問題でも問題が発生する

クロスサイトスクリプティングはSQLインジェクションと異なり、エスケープしてはならない場合やエスケープ方法が異なる場合があります。エスケープしてはならない場合、変数にユーザ入力が含まれているか含まれていないのか、正確に分かっていなければならないですが、システムが設定していると思いがちな変数にユーザ入力が含まれている場合もあります。REQUEST_URI, REFERER, X_FORWARDED_FORなどのWebサーバが設定する値やHTTPヘッダの値は、ユーザが自由に設定できる値なので直接出力してはならない変数です。

例2 XSSに脆弱なPHPコード
<form name="some_form" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">

※$_SERVER['PHP_SELF']にはREQUEST_URI情報が含まれるので直接出力するとXSSに脆弱になる

ユーザ入力を一旦別の変数に代入すると、その変数が危険な変数であることが分かりづらくなります。ユーザ入力を含む変数名が長いからといって短い名前の変数に代入して利用するコードは、危険性が高くなります。

さらに、最近AJAXの普及により、クライアントで複雑なJavaScriptを実行するアプリケーションが増えています。JavaScriptを利用している場合、サーバ側のコードと無関係にクロスサイトスクリプティングに脆弱となる場合があります。

例3 脆弱なJavaScriptコード
document.write(window.location)

実際の脆弱性はこの例のほど単純ではありませんが、JavaScriptのコードがクロスサイトスクリプティング脆弱性を作ってしまうことが分かると思います。

おすすめ記事

記事・ニュース一覧