クロスサイト・スクリプティング

カスタム・タグ・ライブラリーを使って、動的コンテンツをエンコードする

クロスサイト・スクリプティングによるセキュリティー脆弱性の露呈は、潜在的に非常に危険です。セキュアWebベース・アプリケーションを設計するときには、この点をぜひ考慮すべきです。この記事では、この脆弱性露呈の本質と仕掛けについて著者Paulが説明し、推奨される改善策を示します。

Paul Lee (paul@ca.ibm.com), I/T Architect, IBM Global Services

Paul Lee氏はIBM Global ServicesのITアーキテクトで、顧客のWebベース・テクノロジー・アプリケーションに関連した業務に携わっています。連絡先はpaul@ca.ibm.com です。



2002年 9月 01日

最近のほとんどのWebサイトは、ユーザーにもっと楽しんでもらうために、Webページに動的にコンテンツを追加する傾向にあります。動的コンテンツとは、何らかのサーバー・プロセスによって生成されるコンテンツです。こうしたコンテンツは、ユーザーに送られて来るとき、ユーザー側の設定やニーズに応じて個別に異なる動作や表示を行います。動的Webサイトには静的Webサイトにはない危険が伴います。その1つは「クロスサイト・スクリプティング (cross-site scripting、略して "XSS")」と呼ばれる問題です。

「Webページには、サーバーによって生成され、クライアント・ブラウザーによって解釈されるテキストおよびHTMLマークアップが含まれる。静的ページのみを生成するWebサイトは、ユーザーのブラウザーによってページがどのように解釈されるかを完全に制御できる。動的ページを生成するWebサイトは、自分の出力がクライアントによってどのように解釈されるかを完全には制御できない。問題の核心は、もし信頼されないコンテンツが動的ページに挿入された場合、それに気付いて保護措置を取るための十分な情報がWebサイト側にもクライアント側にも得られないことである。」-CERT Coordination Centerはこう説明しています。同センターは、インターネット・セキュリティーの脆弱性を研究し、インシデント (実際の発生事例) への対応策を提供するために、米国連邦政府から財政援助を受けている研究開発センターです。

クロスサイト・スクリプティング攻撃の対象はWebサイトで簡単に見つかるため、アタッカー (攻撃者) たちの間でクロスサイト・スクリプティングの「人気」が高まっています。毎月、多数の商業サイトでクロスサイト・スクリプティング攻撃が発見されており、その脅威を説明したアドバイスも公表されています。Webサイト側がこれに注意を払わなければ、Webサイトの安全な運営は不可能になり、ひいては企業の評判にも損害が及びかねません。

この記事の目的は、この増大する脅威について読者の認識を高め、この種の攻撃を回避するためのソリューションをWebアプリケーションにどのように実装すればよいかを示すことです。

クロスサイト・スクリプティングの脅威

クロスサイト・スクリプティングは、サーバー・アプリケーションに次のような危険をもたらします (なお、危険は下記に限られるわけではありません)。

  • 攻撃者が提供したコンテンツを基に動的に生成されたページをユーザーが閲覧すると、悪意のあるスクリプトが知らないうちに実行される可能性がある。
  • ユーザーのセッションcookieの有効期限が切れる前に、攻撃者はユーザー・セッションを奪うことができる。
  • 攻撃者は、自分の望む悪意あるサーバーにユーザーを接続させることができる。
  • 攻撃者は自分の提供したURLにユーザーをうまく誘導して、攻撃者の望むスクリプトまたはHTMLをユーザーのブラウザー上で実行させることができる。攻撃者はこのテクニックを利用して、URLにアクセスしたユーザーの持つ特権を使って操作を行うことができる (たとえば、SQLデータベースに照会を出してその結果を表示し、ターゲット・システムの既知の欠陥実装につけ込む)。

攻撃を仕掛ける

攻撃者は、あるWebサイトのアプリケーションがクロスサイト・スクリプティングを防げないと判断したら、画策を練り始めます。攻撃者たちに最もよく使われるテクニックは、JavaScript、VBScript、ActiveX、HTML、またはFlashを注入することにより、被害者の持つ特権を使って被害者のシステム上でそれを実行することです。いったん攻撃が開始されると、アカウント乗っ取り、ユーザー設定値の改変、cookieの不正入手と改ざん、あるいは偽りの広告といったあらゆる操作が可能になります。


サンプルの攻撃シナリオ

これからご紹介するいくつかのシナリオ図は、実際にありそうな攻撃パターンを示しています。ただし、これらのパターンの変種をすべて網羅できるわけではありません。文書に明示されたさまざまな攻撃について、およびベンダーやユーザーがどのように攻撃を防御できるかについては、参考文献をご覧ください。

悪意のあるリンクを介したスクリプティング

このシナリオでは、攻撃者は工夫を凝らしたe-mailメッセージを被害者に送り付けます。そのメッセージには、たとえば以下のような悪意のあるリンク・スクリプトが含まれます。

<A HREF=http://legitimateSite.com/registration.cgi?clientprofile=<SCRIPT>悪意のあるコード</SCRIPT>Click here</A>

警戒心のないユーザーがこのリンクをクリックすると、悪意のあるコードとともにURLがlegitimateSite.com (正当なサイト) に送られます。図1 のように、正当なサーバー (legitimate server) が、clientprofile の値を含むページをユーザーに送り返すと、悪意のあるコード (malicious code) がクライアントWebブラウザー上で実行されます。

図1. e-mailを介した攻撃
図1

ユーザーのcookieを盗む

Webサイトのどこかでcookieを使用している場合、cookieをユーザーから盗むことも可能です。このシナリオでは、攻撃者が、悪意のあるスクリプトを含むページを脆弱なサイトの中に埋め込みます。そのページが表示されると、悪意のあるスクリプトが実行されます。スクリプトはユーザーのcookieを収集し、それらのcookieを含んでいる要求を攻撃者のWebサイトに送ります。攻撃者はこの技を利用して、機密データ (パスワード、クレジット・カード番号など、ユーザーが入力する任意の情報) を得ることができます (図2 を参照)。

図2. cookieの盗難およびアカウント乗っ取り
図2

権限のないはずの要求を送る

このシナリオでは、メール・メッセージ内の悪意のあるリンクをユーザーがクリックすると、攻撃者の書いたスクリプトをユーザーが知らずに実行してしまいます。悪意のあるスクリプトは、いかにも正当なサーバーから発せられたかのようなコンテキストで実行されるため、攻撃者は取り寄せられた文書を自由に閲覧でき、ページに含まれるデータを彼らのサイトに送ることができます。
埋め込まれたスクリプトに、被害者側に警告を発せずに正当なサーバーと対話するような追加機能がある場合、攻撃者は送られてきたデータを正当なWebサーバー上の別のページに送って悪用することができます ( 図3 を参照)。

図3. 権限のないはずの要求を送る
図3

攻撃を回避する

すでに述べたように、攻撃者の意図する悪意あるスクリプトを含むページが、正当なWebサーバーによって被害者ユーザーのWebブラウザーに送られたとき、クロスサイト・スクリプティングが発生します。その後、攻撃者は正当なWebサーバーが正当なスクリプトに与える特権を使って、悪意のあるスクリプトを実行させることができます。

攻撃の基本的パターンがわかったところで、次は、私たち自身をどのように守ればいいのでしょうか。

Webサイト開発者が自分たちのサイトをこうした攻撃から守るには、動的に生成されるページに望まれないタグが決して含まれないようにする必要があります。

Webユーザーの側では、こうした被害を受ける危険を減らすために、2つのオプションがあります。第1に、Webブラウザー、およびHTMLを使用可能な電子メール・クライアントで、スクリプト言語を使用不可 (無効) にすることです。これは最も強固な保護策ですが、機能が制限されるという副作用もあります。第2に、リンクをクリックするときは、メインWebサイト内からのリンクだけを利用することです。この方法は、機能を維持しながら、ユーザーの危険をかなり低減させます。

しかしながら、Webユーザーが取り得る解決策は、どれも完ぺきではありません。結局のところ、この種の問題を防ぐには、Webページ開発者たちがページを改訂するかどうかにかかっています。つまり、ページに入力されるデータを適切にフィルタリングまたは妥当性検査を行い、ユーザーに戻される出力を適切にエンコードするかフィルタリングする必要があります。

フィルタリングによる対策

この手法の基本概念は、ユーザー入力を絶対に信頼しないことと、HTML仕様で定義されたメタ文字 (「特殊な」文字) を必ずフィルターに掛けることです。それぞれの入力フィールド (リンク・パラメーターを含む) を検査して、スクリプト・タグがないかどうか調べます。スクリプト・タグが見つかった場合、コンテキストに応じて入力データを拒否します。こうして、悪意あるHTMLがユーザーに送られるのを防げます。

事態をより複雑にしているのは、多くのWebブラウザーが、HTMLのよくあるエラーを訂正しようとすることです。その結果、仕様によれば特殊ではない文字を、ブラウザーが特殊文字として扱う場合があります。したがって、個々の状況によっては、特殊文字に追加の文字が含まれるかもしれないことに注意しなければなりません。Web開発者は自分たちのアプリケーションをよく調べて、どんな文字がそのWebアプリケーションに影響するかを判別する必要があります。

入力側のフィルタリングは、それほど効果的ではありません。なぜなら、HTTP以外の方法で動的コンテンツをWebサイトのデータベースに挿入することが可能だからです。その場合、Webサーバーがそのデータをデータ入力の一部と見なすことは決してなく、データ要素は汚染されたままになります。それに代わる方法として推奨されるのが、データ出力処理でのフィルタリングです。動的ページの一部としてレンダリングされる直前に、フィルターに掛けるわけです。この方法を正しく利用すれば、すべての動的コンテンツが確実にフィルターに掛けられます。

エンコーディングによる対策

生成されるページで意図されないスクリプトが決して実行されないよう、Webサーバーが適切なエンコードを行うならば、クロスサイト・スクリプティング攻撃を防ぐことは可能です。

ISO-8859-1規格のそれぞれの文字は、数値の入力値を使ってエンコードできます。サーバー・サイド・エンコーディングとは、エンコーディング機能を介してすべての動的コンテンツを生成する手法です。その場合、スクリプト・タグは、選択された文字セットのコードに置き換えられます。

一般的に言って、エンコードすることが推奨されます。なぜなら、正当な入力データとしてどんな文字を受け入れ、次の処理段階に送るべきかを決定しなくていいからです。残念ながら、信頼されないすべてのデータをエンコードするとリソースを大量に消費し、一部のWebサーバーではパフォーマンスに影響が及ぶ可能性もあります。


あなたに適したストラテジーは ?

CGIベースのWebアプリケーション、あるいはブラウザーにおいてフィールド編集検査を行うアプリケーションでは、フィルタリングによる方法を採用するのがいいでしょう。既存のフィールド編集検査を拡張して、クロスサイト・スクリプティング攻撃を防御するわけです。ブラウザー側でフィールド編集検査を行うと、サーバーとのやり取りがいくらか少なくなるという利点がありますが、この方法が有効なのはユーザーが信頼できる場合のみです。しかも、推奨されている修正を実現するためには、すべての入力フィールドが必ず検査されるようコードを入念に吟味しなければなりません。一方、サーバー・サイドで妥当性検査するよう設計されたWebアプリケーションの場合は、いずれか (または両方) の方法を採用することができます。

フィルタリングによる方法が正しく効果を発揮するには、アプリケーションのニーズに応じて、Web開発者 がフィルタリングのメタ文字のリストを常に最新に保つ必要があります。一方、エンコーディングによる方法の場合は、上記のようなメインテナンスの手間が不要です。しかも、既存のアプリケーション・コードやアプリケーション機能に与える影響がより小さくなります。こうした理由で、エンコーディングによる方法の方が実装に向いているようです。サンプルのエンコーディング実装を以下に示しましょう。


単純なエンコーディング例

生成されるページが正しくエンコードされるようWebサーバーで管理するための、シンプルかつ効果的な1つの方法は、動的コンテンツのそれぞれの文字をエンコーディング機能に送ることです。そうすれば、動的コンテンツ内のスクリプト・タグは、選択された文字セットのコードに置き換えられます。この種のタスクは、カスタム・タグ・ライブラリーで実行するのが最適です。

カスタム・タグ・ライブラリーの基本

カスタム・タグ・ライブラリーは、1つまたは複数のJava言語で書かれたクラス (これをタグ・ハンドラーという) と、XMLタグ・ライブラリー記述ファイル (tag library description file、TLD) から構成されます。TLDは新しいタグ名と、それらのタグの有効な属性値を記述します。タグ・ハンドラーとTLDは、JSPページ内部から要求されたとき、タグ、タグの属性、およびタグ付けされている本文がどのように解釈されて処理されるかを決定します。カスタム・タグ・ライブラリーは、複雑な操作をカプセル化するうえで、Java beanよりも柔軟なアーキテクチャーを可能にします。


我々の要求に最適の「カスタム」タグ・ライブラリー

このカスタム・タグ・ライブラリーには、XSS という名前が最も似合っています。タグ・ライブラリーは、サーブレット・コンテナーに組み込まれるソフトウェア・コンポーネントです。サーブレット・コンテナーはタグ・ハンドラーを作成し、初期化した後、doStartTag()doEndTag()、およびrelease() メソッドを (この順番) で呼び出します。

XSSカスタム・タグ・ライブラリーはこうしたやりとりを通して、JSPページ内に見つかる動的データをエンコードするための「カスタム」アクションを行います。カスタム・タグの実装は単純で、次のような手順で行います。

  • タグを記述するタグ・ライブラリー記述子(.tld) を作成する。
  • タグを使用するJSPファイルに、taglib のディレクティブ指定を追加する。
  • TagSupportを継承するタグ・ハンドラーを実装して、doStartTag() メソッドまたはdoEndTag() メソッドをオーバーライドする。

TLD (タグ・ライブラリー記述子)

タグ・ライブラリー記述子 (tag library descriptor) はXMLファイルであり、その要素によってある特殊なタグ・ライブラリーを記述します。カスタム・タグ・ライブラリーXSS のTLDがリスト1 に示されています。tag要素はencode アクションを定義し、これには属性、property が含まれます。tagclass 要素はタグ・ハンドラー・クラスEncodeTag を定義します。

リスト1. xss.tldファイル
<?xml version="1.0" encoding="UTF-8"?>
 DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" 
	"http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
 
<taglib>
     <tlibversion>1.0</tlibversion>
     <jspversion>1.1</jspversion> <tag>
        <name>encode</name>
        <tagclass>dw.demo.xss.EncodeTag</tagclass>
        <bodycontent>empty</bodycontent>
        <attribute>
            <name>property</name>
            <required>true</required> </attribute>
     </tag>
</taglib>

taglib 指定子

taglib 指定子はタグ・ライブラリー記述子を識別して、後続のタグをライブラリーに関連付けるタグ接頭辞を定義します。カスタム・タグ・ライブラリーXSS 内のJSPに含まれるサンプルtaglib 指定子は、以下のとおりです。

   <%@ taglib uri="/WEB-INF/tlds/xss.tld" prefix="xss" %>

タグ・ハンドラーのコーディング

タグ・ハンドラーはWebコンテナー内のオブジェクトで、JSPページが実行されるときのアクションの評価を支援します。EncodeTag クラスは、エンコード・アクション用のタグ・ハンドラーです。この中のdoStartTag メソッドは、リスト2 に示されるように、動的コンテンツをISO-8859-1文字セットにエンコードします。

リスト2. 動的コンテンツのエンコーディング
 public int doStartTag() throws JspException {
      StringBuffer sbuf = new StringBuffer();
     char[] chars = property.toCharArray();
     for (int i = 0; i < chars.length; i++) { sbuf.append("&#" + (int) chars[i]);
     }     
     try{
          pageContext.getOut().print(sbuf.toString());     } catch (IOException ex) {
          throw new JspException(ex.getMessage());     }     
     return SKIP_BODY;
 }

デプロイメント

Webアプリケーションの一部であるXSS カスタム・タグ・ライブラリーは、追加ファイルとしてWebアプリケーションのWARファイルに以下のようにパッケージされます。

  • WEB-INF/lib/encodetaglib.jar
  • WEB-INF/tlds/xss.tld

実際に使用する

以下のシナリオは、カスタム・タグ・ライブラリーの実際の使用例を示しています。ここでは、さまざまな記事を受信するWebサイトを想定し、ユーザーが購読を申し込んだ記事を表示するためのページが1つ存在するとします。動的コンテンツ、つまり個別ユーザーのために意図された記事項目が、JSPファイル内の<%= expression %> 構文を使って生成されます。

さて、ある攻撃者が購読者用Webサイトの中に、悪意あるスクリプトを含むページを埋め込むことに成功したとします。この攻撃が成功した結果、ユーザーのブラウザー上で実行すると、図4 のようなポップアップ・ウィンドウが表示されます。

図4. エンコード前
図4

次のシナリオでは、仮想Webサイトがカスタム・タグ・ライブラリーXSS を使用することによって、生成されるページを必ずエンコードして攻撃から身を守るよう対策を立てます。信頼されないデータは、図5 のように、ブラウザー内にコードのまま表示されます。

図5. エンコード後
図5

要約

この記事では、攻撃者がWebサイトへの攻撃手段としてクロスサイト・スクリプティングを利用する方法について説明しました。さらに、Webサイト側が単純なカスタム・タグ・ライブラリーを使って動的コンテンツを適切にエンコードすれば、ほとんどの攻撃を回避できることも示しました。カスタム・タグ・ライブラリーXSS はそのまま使用することもできますが、Webアプリケーションのニーズに合わせて調整するとより効果的でしょう。このような方法で、この新たな脅威から身を守ってください。

参考文献

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Tivoli (service management), Java technology
ArticleID=224174
ArticleTitle=クロスサイト・スクリプティング
publish-date=09012002