マッシュアップのセキュリティー

マッシュアップでの UI 成果物とデータをセキュアにするための技術と手法

マッシュアップを利用した開発モデルにより、Web の世界に膨大な可能性が生まれます。その一方で、マッシュアップの持つオープンな性質から、新たなセキュリティーの脆弱性が大量に発生します。この記事では、こうした問題のいくつかに対処するためのヒントと手法を説明します。

J. Jeffrey Hanson, CTO, Max International

Jeff HansonJeff Hanson はソフトウェア業界を 20 年以上経験してきています。経験した業務の中には、OpenDoc プロジェクトでの Microsoft® Windows® への移植でのシニア・エンジニア、Novell での Route 66 フレームワークのアーキテクト・リーダー、eReinsure.com, Inc. でのチーフ・アーキテクトなどがあります。彼は現在、Max International の CTO (最高技術責任者) として、小売業界や卸売業界用のエンタープライズ・アプリケーションやプラットフォームの設計と実装を指揮しています。彼は数多くの記事や本を執筆しており、その中には『.NET versus J2EE Web Services: A Comparison of Approaches』や『Pro JMX: Java Management Extensions』、『Web Services Business Strategies and Architectures』、『Mashups: Strategies for the Modern Enterprise』などがあります。


developerWorks 貢献著者レベル

2009年 8月 04日

マッシュアップはアプリケーションであると同時に Web ページでもあり、多様な、そして多くの場合は公開されているソースから UI 成果物とデータを集約することで構築されます。マッシュアップを利用した開発モデルによってオープンな開発モデルが導入されますが、それと共に多くの新しいセキュリティー・リスクも発生します。こうした新しいリスクのため、マッシュアップ・アプリケーションを開発する際にはセキュリティーが最重要課題となります。

よく使われる頭字語

  • DMZ: Demilitarized zone
  • DOM: Document Object Model
  • HTML: Hypertext Markup Language
  • HTTP: Hypertext Transfer Protocol
  • SQL: Structured Query Language
  • SSL: Secure Sockets Layer
  • UI: User interface

DMZ やファイアーウォールといった従来のセキュリティー手段は、マッシュアップの UI 成果物やデータに要求されるきめ細かなアクセスに対応するには十分ではありません。マッシュアップ・アプリケーションまたはマッシュアップ・ページが対処しなければならない問題には、CSRF (クロスサイト・リクエスト・フォージェリー)、Ajax (Asynchronous JavaScript™ + XML) の脆弱性、XSS (クロスサイト・スクリプティング)、その他潜在的なセキュリティーの弱点などがあります。

この記事では、マッシュアップ・アプリケーションやマッシュアップ・ページを作成する際に対処すべきセキュリティーの問題について調べます。

なぜマッシュアップにセキュリティーが必要なのか

マッシュアップを利用したページまたはアプリケーションは、1 つ以上の内部サイトまたは外部サイトのデータと UI 成果物を、通常はその時だけ組み合わせることで作成されます。この開発モデルによってセキュリティーの脆弱性が生じ、この脆弱性が瞬く間に何倍にもなります。つまり新しい成果物やデータ・ソースがマッシュアップに追加されるたびに、セキュリティーの脆弱性が拡大します。こうしたオープンな統合では、悪意のある侵入に対して成果物やデータをテストして確実にセキュアなものにすることが絶対に不可欠になります。

マッシュアップ・ページが他のマッシュアップのコンポーネントまたはデータ・ソースとして使われる場合もあります。そのため、マッシュアップの成果物やページ、データ・ソースが時間の経過と共にどのように使われるかを正確に予測することは困難です。従って、マッシュアップに使われるすべてのコンポーネントとプロセスでセキュリティーに対処することが欠かせません。

ユーザー入力のセキュリティー

SQL インジェクション、CSRF、XSS などの侵入に対する脆弱性の多くは、包括的な入力検証フレームワークを使用することで防ぐことができます。

サーバー・サイドでのマッシュアップ検証フレームワークとクライアント・サイドでのマッシュアップ検証フレームワークは、入力データの処理方法の点で相互補完的でなければなりません。クライアント・サイドの検証は極めて非常に容易に回避できてしまうため、データとプロセスを保護する上で、サーバー・サイドでの包括的で補完的な検証も非常に重要な要素です。

入力検証フレームワークが効果的なものであるためには、以下のことが必要です。

  • 入力データを制限できる、限定的な値のリストを定義する。
  • 入力データの型、データの長さ、データの範囲、データのフォーマットを検証する。
  • クライアントとサーバーで正規表現を使用し、一貫性のある検証モデルを実現する。
  • 無効な文字が入力されないよう、入力データをサニタイズする。

オンデマンド・スクリプティングによる攻撃を回避する

多くのマッシュアップで使われている方法の 1 つとして、オンデマンドで動的にダウンロードされて解釈される JavaScript スニペットを埋め込む方法があります。オンデマンドのスクリプトには、セキュリティーの脆弱性を悪用した悪意のあるコードが含まれている可能性があります (例えば XSS など)。こうした脆弱性の悪用を防ぐためには、オンデマンド・スクリプトが検証ずみであること、そしてそのスクリプトから生成されたコンテンツが適切にエンコードされていることを確認し、悪意のあるコードが実行されないようにします。リスト 1 はエンコードされていないマークアップの例です。

リスト 1. エンコードされていないマークアップの例
  <div>
  This is example content
  </div>

上記のスニペットをエンコードしたバージョンがリスト 2 です。

リスト 2. エンコードされたマークアップの例
  &lt;div&gt;
  This is example content
  &lt;/div&gt;

上記のように、動的に生成されたスクリプトを使用するマッシュアップ・ページは、そのスクリプトが生成したデータが検証ずみであること、そしてエンコードされていることを確認し、ブラウザーがそのデータをHTML のマークアップまたはスクリプト・コードとして解釈しないように保証する必要があります。ブラウザーがそのデータを誤って解釈すると、悪意のあるコードが実行され、セキュリティーの侵害が発生する可能性があります。

データが検証もエンコードもされていない場合には、以下のように脆弱性を悪用されるリスクがあります。

  • データの完全性が侵害される
  • 侵入者がクッキーを作成する、あるいはクッキーにアクセスする
  • 侵入者がユーザー入力をインターセプトし、ユーザー入力にアクセスする
  • 信頼されるドメインあるいはコンテキストの中で悪意のあるスクリプトが実行される

また、解釈される各コンテキストをインテリジェントに分析する必要があります。そうすることで、それぞれの特定のコンテキストで問題を引き起こす可能性のある文字群のみに対応すればよくなります。

セッションの固定化を防ぐ

最初に既存のセッションを無効にせずにサーバーでユーザー認証をすると、いわゆるセッション固定化を引き起こす可能性があります。セッションが固定化されると、侵入者は認証済みのセッションをインターセプトしたり新しいセッションを作成したりすることができ、セッション ID を取り込むこともできます。すると、正規のユーザーがセッションを作成する際にそのセッション ID が悪意で使用され、同じセッション ID が使われてしまいます。

リスト 3 の Java™ コードでは、最初に既存のセッションを無効にせずにクライアント・リクエストを認証しています。

リスト 3. セッション固定化による脆弱性の例
  private boolean authenticateUser(HttpServletRequest req)
  {
    // session.invalidate() should have been called prior to this
    // to invalidate an existing session

    HttpSession session = req.getSession(false);
    if (null != session)
    {
      // existing session assumed valid
      return true;
    }

    if (authenticateRequest(req) == true)
    {
      // create a new session
      req.getSession();
      return true;
    }
    
    return false;
  }

リスト 3 では、既存のセッションが無効にされていないため、現在のリクエストに対してこのセッションが有効であると見なされています。こうした状況では、新しいユーザーが認証用クレデンシャルをサーバーに提供する際に、この状況が悪用される可能性があります。つまり、既存のセッションを開始したユーザーは、そのセッションが有効である限り、セッション上を流れるデータを記録することも、場合によっては悪用することもできてしまうのです。

このタイプの攻撃を防ぐためには、以下のような手法があります。

  • セッションのタイムアウトを指定する
  • ログアウトを明示的に表す UI コントロールを使ってセッションを無効にするように促す
  • プライバシーが非常に重要な場合には、ユーザーに必ずクレデンシャルを再度入力させる
  • リクエストごとにセッション ID を再生成する

この状況はマッシュアップ・ページへの侵入者によって悪用されることが多く、彼らはブラウザーによる制約を回避して機密データをリダイレクトし、そのデータを記録します。この攻撃はクロスサイト・スクリプティングとして知られています。

CSRF 攻撃を防ぐ

CSRF 攻撃は侵入者のサイトからの悪意のあるコードから発生し、ブラウザーを騙すことによって、信頼されるサイトに対して不当なリクエストを送信させます。ブラウザーによる SOP (Same-Origin Policy: 同一生成元ポリシー) では、異なる生成元サイト『から』送信されるリクエストを阻止することはできず、異なる生成元サイト『に』送信されるリクエストを阻止することしかできません。従って、SOP によって CSRF 攻撃を防ぐことはできません。

CSRF 攻撃の拠り所となっているのは、サーバーが、元々認証セッションを開始したブラウザーから送信されるすべてのリクエストは有効である、と見なす点です。典型的な認証メカニズム (ユーザー名とパスワード、クッキー、SSL 証明書など) は、CSRF 攻撃から保護する上では十分ではありません。なぜなら、これらのメカニズムはブラウザーとサーバーとの間のセッションを認証することを前提にしており、個々のリクエストとサーバーとの間での認証を前提にしていないからです。

CSRF 攻撃が行われている間、侵入者のサイトから送られてきたリクエストは、認証されたブラウザー・ページを介してサーバーに送信されます。そしてレスポンスは、知らないうちに侵入者のサイトに送信されます。CSRF 攻撃が行われている間のリクエストとレスポンスのシーケンスを示したものが図 1 です。

図 1. CSRF 攻撃が行われている間のイベントのシーケンス
CSRF 攻撃が行われている間のイベントのシーケンス

図 1 は、侵入者のサイトが、認証されたマッシュアップ・ページを介してマッシュアップ・サーバーにリクエストを発行する様子を示しています。この攻撃を可能にするための唯一の方法は、侵入者のサイトがマッシュアップ・ページをプロキシーとして動作させ、侵入者のサイトに代わって会社のマッシュアップ・サーバーにリクエストを行う方法です。これは HTML のさまざまな手法を使うことで実現することができます。

CSRF 攻撃を実行するために侵入者が使用する手法の 1 つが、<img> タグの src 属性の中に URL を埋め込む方法です。この <img> タグをブラウザーが評価すると、その URL が参照されます。データは、その URL が参照するホストに渡されます。例えば、下記の <img> タグを見てください。

<img src="http://mybank/transfer?amount=10000&fromaccount=44332&toaccount=55443">

mybank に対して認証されたセッション中に上記の <img> タグを含むページがアクセスされると、この <img> タグは評価され、src 属性によって指定される URL を参照します。すると、要求されたアクションが実行されます。

このタイプの CSRF 攻撃を防ぐためには、mybank のサーバーは HTTP GET リクエストを使って変更を開始するのではなく、POST リクエストのみを使って変更を開始するようにします。

CSRF 攻撃を防ぐためにマッシュアップ・サーバーでよく使われる手法として、各HTTP リクエストにリクエスト専用のトークンを含めるようにし、そのトークンを各 POST リクエストと GET リクエストと共にサーバーに送信するように要求する手法があります。

JSON データのセキュリティー

JSON (JavaScript Object Notation) は JavaScript プログラミング言語の構文に従うデータ構造です。従って、ほとんどすべての標準的な JavaScript の関数や文を使って、JSON データを処理することができます。特に、JSON データの処理に使用することができ、実際によく使用される関数が eval() 関数です。

リスト 4 は簡単な JSON データ・ブロックの例です。

リスト 4. JSON データ・ブロックの例
  [
    {
      name: "object1",
      message: "Greetings from object1",
    },
    {
      name: "object2",
      message: "Greetings from object2"
    },
    {
      name: "object3",
      message: "Greetings from object3"
      code: alert("This will be executed when evaluated!")
    },
    {
      name: "object4",
      message: "Greetings from object4"
    },
    {
      name: "object5",
      message: "Greetings from object5"
    }
  ]

上記の JSON データが評価されると、object3 という名前のオブジェクトに埋め込まれた JavaScript の命令が実行されます。この機能はマッシュアップ・サーバーやマッシュアップ・アプリケーションでよく利用され、XMLHttpRequest オブジェクトによるリクエストに対して、レスポンスをサーバーからブラウザーに送信する際のデータ・フォーマットとして JSON を使うために利用されます。しかしこのメカニズムは、いくつかの重大なセキュリティーの脆弱性も持っています。

上で述べたように、JSON データ・ブロックに埋め込まれたすべての JavaScript の命令は、そのデータ・ブロックが解釈されると即座に実行されます。JSON データの処理には JavaScript 言語の eval() 関数がよく使われます。下記はその一例です。

var jsonObject = eval('(' + httpReqResponse + ')');

JSON データ・ブロックに埋め込まれ、eval() 関数によって処理された命令は、即座に実行されます。そのデータに悪意のあるコードが含まれていた場合には、マッシュアップ・ページ上にある機密データが悪意のある者の手に渡る可能性があります。また、悪意のあるコードがマッシュアップ・ページの制御を奪うこともできます。

JSON データの悪用を防ぐための方法はいくつかあります。下記はその一部です。

  • JSON データ・ブロックの前に無限の while ループを置く
  • JSON データ・ブロックを JavaScript のコメントでラップする
  • JSON データ・ブロックの処理に eval() 関数を使わないようにする

リスト 5 は JSON データ・ブロックの前に while(1); という文を置く例を示しています。この手法を使う場合には、クライアントは JSON データを使用する前に while(1); 文を削除し、無限ループを回避する必要があります。

リスト 5. while ループにラップされた JSON データ・ブロックの例
  while(1);
  [
    {
      name: "object1",
      message: "Greetings from object1",
    },
    {
      name: "object2",
      message: "Greetings from object2"
    },
    {
      name: "object3",
      message: "Greetings from object3"
      code: alert("This will be executed when evaluated!")
    },
    {
      name: "object4",
      message: "Greetings from object4"
    },
    {
      name: "object5",
      message: "Greetings from object5"
    }
  ]

標準的な eval() 関数の代わりに、JSON ライブラリーに用意されている JSON.parse() 関数を使うことができます (「参考文献」を参照)。リスト 6JSON.parse() 関数を使って JSON データを処理する例を示しています。

リスト 6. JSON.parse 関数の例
  <script type="text/javascript" src="js/json2.js"></script>
  var jsonObject = JSON.parse(httpReqResponse);

リスト 7 は JavaScript のコメントの中にラップされた JSON データ・ブロックを示しています。クライアントは JSON データを使う前に、これらのコメントを解除する必要があります。

リスト 7. JavaScript のコメントの間にラップされた JSON データ・ブロックの例
/*
[
  {
    name: "object1",
    message: "Greetings from object1",
  },
  {
    name: "object2",
    message: "Greetings from object2"
  },
  {
    name: "object3",
    message: "Greetings from object3"
    code: alert("This will be executed when evaluated!")
  },
  {
    name: "object4",
    message: "Greetings from object4"
  },
  {
    name: "object5",
    message: "Greetings from object5"
  }
]
*/

iframe のセキュリティー

埋め込みのインライン・フレーム (iframe) としてマッシュアップ・ウィジェットを実現することがよくあります。iframe は HTML 要素ですが、ブラウザーは iframe をページ内の別のエンティティーと見なします。iframe 内部に配置されたコンテンツは、そのコンテンツを包含する iframe の外にあるブラウザーの DOM をまったく操作することができません。そのため iframe は、マッシュアップ・ページ内に含まれている可能性のある、悪意のあるコンテンツを隔離するために、マッシュアップ・ウィジェットや他の UI 成果物としてよく使われます。

リスト 8 は典型的な iframe 要素の 2 つの例です。

リスト 8. 典型的な iframe 要素の例
  <iframe src="http://jeffhanson.com/iframe1.html" />
  <iframe src="http://jeffhanson.com/iframe2.html" />

iframe は通常、視覚要素として使われ、枠の付いた UI コンポーネントとしてブラウザー・ページに表示されます。その一方で iframe は、ブラウザー・ページ内でのメッセージングの制御手段として、非表示にして使われることがよくあります (図 2)。

図 2. iframe とマッシュアップ・ページとの間でのデータの受け渡し
iframe とマッシュアップ・ページとの間でのデータの受け渡し

この図は、jeffhanson.com/index.html にある HTML ページを示しています。このページの DOM の中に隠し iframe が埋め込まれており、この iframe は jeffhanson.com/test.html にあるコンテンツから構成されています。この隠し iframe の src URL は、JavaScript 関数 sendData() によってhttp://jeffhanson.html#data に設定されます。この src URL のフラグメント識別子 (#) の後にある部分を (onLoad イベントに対して定義された関数からわかるように) window.location.hash 要素を使って取得することができます。このメカニズムを使うと、index.html ページがロードされた時に、隠し iframe はフラグメント識別子の後にあるデータを取得することができます。この手法は、iframe 間で、あるいは HTML ページと埋め込まれた iframe との間でデータを送信するためによく使われます。

上で説明した、この iframe によるデータ送信メカニズムによって、セキュリティーの脆弱性が生じます。iframe を含む HTML ページ内にある任意のコンポーネントが src URL を設定できるため、悪意のあるコードを含む UI 成果物をページ内に埋め込むことによって、そのページ内に含まれたデータのプライバシーを侵害することができ、場合によってはメインの HTML ページの生成元であるサーバーとも通信できてしまいます。

iframe フラグメント識別子による攻撃を防ぐためには、次のようないくつかの手法があります。

  • ホワイト・リストにあるドメイン以外はフラグメント識別子を変更できないようにする
  • フラグメント識別子データを公開鍵を使って暗号化する
  • フラグメント識別子データを JavaScript コードを使ってフィルタリングする
  • フラグメント識別子データに埋め込まれた JavaScript コードが不正に実行されることがないようにする

まとめ

マッシュアップはアプリケーションであると同時に Web ページでもあり、多様な、そして多くの場合は公開されているソースから得られる UI 成果物とデータから構成されています。マッシュアップの開発モデルは非常にオープンな環境で操作が行われるため、そこに多くの新たなセキュリティー・リスクが生じます。こうした新しいリスクのため、マッシュアップ・アプリケーションを開発する際にはセキュリティーが最優先課題になります。

マッシュアップ・アプリケーションまたはマッシュアップ・ページは、CSRF、Ajax の脆弱性、XSS、その他潜在するセキュリティーの弱点に対処する必要があります。DMZ やファイアーウォールといった従来のセキュリティー手段は、マッシュアップの開発に必要なセキュリティー要件に対応するためには十分ではありません。この記事では、マッシュアップ・アプリケーションやマッシュアップ・ページを構築する際のセキュリティーの問題に対処するための手法について説明しました。

参考文献

学ぶために

製品や技術を入手するために

  • JSON に関する情報、また必要なライブラリーを JSON.org で入手してください。
  • IBM 製品の試用版をダウンロードし、DB2® や Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品をお試しください。

コメント

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=Web development
ArticleID=426805
ArticleTitle=マッシュアップのセキュリティー
publish-date=08042009