前回はWeb開発に不慣れな開発者が行いがちな、不適切なクロスサイトスクリプティング対策を紹介しました。今回は適切な対策を理解するために必要な、クロスサイトスクリプティングの本質とクロスサイトスクリプティングの種類について解説します。
クロスサイトスクリプティングの名称
「クロスサイトスクリプティング 」は、よくある攻撃方法を表した名前です。サイトをまたがって攻撃用のJavaScriptコード(スクリプト)を送るので、「 クロスサイト」「 スクリプティング」と命名したものと考えられます。
単語の頭文字を取ると「CSS」となりますが、カスケーディングスタイルシートの「CSS」と同じになり、区別できないので「XSS 」と表記されるようになりました。クロスサイトスクリプティングの解説情報には「XSS」ではなく「CSS」と表記している場合もあります。
しかし残念ながらこの名前は直感的な名前とはいえません。初めてこの名前を聞いて、どのような攻撃があり、どのように対処を行えばよいのか直感的に分かる人はいないと思います。
図1 典型的なクロスサイトスクリプティング攻撃
クロスサイトスクリプティングは悪意のあるJavaScriptコードやVBScriptコードをHTMLやCSSに挿入することにより攻撃を行います。ほかのWebアプリケーション脆弱性の代表である、悪意のあるSQLコードを挿入するSQLインジェクション、悪意のあるコマンドを挿入するコマンドインジェクションと同じ「挿入型」の攻撃です。
主にJavaScriptを挿入する攻撃が多いため、JavaScriptインジェクション とも呼ばれます。OWASP (Open Web Application Security Project)では、SQL, XML, LDAP, JavaScript, VBScript等、広い意味でのインタープリタにコードを挿入する攻撃であるので「インタープリタインジェクション 」と呼ぶ呼び方もあります。「 インタープリタインジェクション」を「スクリプトインジェクション 」と呼ぶ場合もあります。PHP、Perl、Rubyのコード挿入攻撃もスクリプトインジェクション攻撃と呼ばれています。
Internet ExplorerにはVB Scriptのインジェクションも可能なので、脆弱性の呼称としてはJavaScriptインジェクションよりスクリプトインジェクションのほうがより的確な名前と考えています。あまり一般的とは言えませんが、本記事ではクロスサイトスクリプティングではなくスクリプトインジェクションを脆弱性名として利用することにします。
スクリプトインジェクションの原因・対策
スクリプトインジェクションはほかのインジェクション攻撃と同じく、完全なバリデーションとエスケープで防御できます。
スクリプトインジェクションはHTML生成のバグ、スクリプトのバグ(後述するType0の脆弱性)のみでなく、以下の機能にバグがあると発生します。
ブラウザ本体 Internet Explorer, Firefox, Opera, Safariなど
インタープリタ JavaScript, VBScriptなど
プラグイン Flash, Shockwave, Silverlight, Quicktime, Acrobat, Windows Media Playerなど
Webアプリケーション開発者としては、インタプリタ自身(ブラウザ)やプラグインのバグに十分な回避策を講じるのは難しいです。ブラックリスト方式では制御した状態で安全性を保つのは非常に困難です。ホワイトリスト方式であれば予測不能なブラウザのバグであっても自然と回避できる場合が多くあります。例えば、「 javascript」という文字列の途中に改行、ヌル文字等の制御文字が挿入されていても、ブラウザが「javascript」という一続きの文字列として解釈してしまうようなバグは、ホワイトリスト方式で完全にバリデーションするとかなり回避できます。
Webアプリケーション開発者は可能な限りブラウザ等のバグを回避し、Webアプリケーション開発者の責任範囲であるサーバサイドスクリプト(HTML生成)とクライアントサイドスクリプト(JavaScript、VBScript)にスクリプトインジェクションが可能な脆弱性を作ってはなりません。
ブラウザに対するスクリプトインジェクションの種類
プラグインやブラウザの機能を除くと、スクリプトインジェクションには大きく分けて3種類の攻撃経路があります。あまり一般的とは言えませんが、それぞれType0、Type1、Type2と呼ばれています。
Type0
DOMベーススクリプトインジェクション、ローカルスクリプトインジェクションとも呼ばれるタイプの脆弱性です。クライアント側で入力値を含む値を出力する場合に発生する脆弱性です。スクリプトインジェクションはサーバ側プログラムに不備がなくても攻撃可能な場合があります。例えば、JavaScriptにはwindow.locationオブジェクトがありますが、このオブジェクトのプロパティにはユーザが任意に設定した値が含まれます。これらのプロパティをそのままブラウザに出力すると、スクリプトインジェクションが可能になります。
図2 Type0のスクリプトインジェクション
Type1
攻撃用のURLやページを経由して不正なJavaScriptコードを挿入するスクリプトインジェクションです。ブラウザからの入力を適切にバリデーションせず、エスケープしないために発生する脆弱性です。攻撃用のURLやページを経由しないと攻撃が行われないので、一時的な攻撃と言えます。
図3 Type1のスクリプトインジェクション
Type2
攻撃用のURLやページを経由しないで不正なJavaScriptコードを挿入するスクリプトインジェクションです。Webサイトがブラウザなどからの入力をデータベースなどに保存し、ブラウザに出力している場合に発生する脆弱性です。Type1と異なり脆弱性があるページを表示したブラウザ全てに攻撃可能で、永続的な攻撃になります。
図4 Type2のスクリプトインジェクション
Type0のスクリプトインジェクション
この脆弱性の危険性はAJAXの一般化とともに増しています。AJAXアプリケーション構築の経験がない開発者の多くは、スクリプトインジェクション(クロスサイトスクリプティング)は知っていてもType0のスクリプトインジェクション脆弱性の知識が十分でないケースが多くあります。
<div id="test">test</div>
<script>
// Safe - IE6, IE7, Firefox, Safari
document.getElementById("test").innerHTML = window.location.href;
// Unsafe - IE6
document.write(window.location.href);
</script>
上記のコードを
http://localhost/xss.html?<script>alert('XSS')</script>
等としてアクセスすると、ブラウザがIE6の場合、JavaScriptが実行されます。
Type1のスクリプトインジェクション
古典的なスクリプトインジェクションです。Type1のスクリプトインジェクションは非永続的なスクリプトインジェクションとも呼ばれています。攻撃を行うには毎回攻撃用のURLやページを経由しなければなりません。被害にあうユーザが攻撃コードを含むページやURL クリックしなければ攻撃されません。
Type2のスクリプトインジェクション
アプリケーション/サイトの種類に関わらず、「 すべて」のスクリプトインジェクション脆弱性は必ず修正されるべきセキュリティ上の重大な問題ですが、Type2の脆弱性はType1に比べさらに大きな危険性を持っています。Type2の脆弱性は永続的スクリプトインジェクションとも呼ばれ、攻撃対象ページ(正規のサイト)を参照したユーザすべてが被害にあう可能性があります。
プラグインを必要とするファイルのサポート
プラグインを必要とするファイルのアップロードをサポートする場合、サイトのセキュリティがプラグインの完成度に依存してしまいます。例えば、MySpaceのJavaScriptワームはQuickTimeファイルをサポートしていたために発生しました。アプリケーションの設計にはこのようなリスクも考慮した上でプラグインをどのように利用するか決定しなければなりません。セキュリティが優先するサイトでは、プラグインを必要とするデータをユーザから受けとって公開しないほうがよいです。
まとめ
今回はクロスサイトスクリプティングより脆弱性の内容がイメージしやすい脆弱性名である「JavaScriptインジェクション」「 スクリプトインジェクション」を紹介しました。名前が変わるだけで具体的な攻撃方法がイメージできるようになった方もいるのではないでしょうか? スクリプトインジェクションの種類を知ることにより、どのように攻撃されるのかよりよく理解できると思います。
今後の本連載では可能な限り“ ブラウザに対する「スクリプトインジェクション」” 脆弱性と記述し、「 クロスサイトスクリプティング」を脆弱性名として利用しないようにします。