セキュアな Ajax マッシュアップの将来を形成する
混成 Web アプリケーション用にブラウザーを改善する方法
Ajax を使ってマッシュアップする
マッシュアップは、複数のソースからのコンテンツを統合して 1 つのページ上に表示する Web アプリケーションです。サーバーは各コンテンツ・ソースにリクエストを送信し、それに対して受信した情報を解析し、その結果を 1 つのページに合成して、それをブラウザーに送信します (図 1)。
図 1. 複数ソースからのコンテンツをマッシュアップする

Ajax (Asynchronous JavaScript + XML) アプリケーションでは、Web ページはサーバーからコンテンツを取得し、ページ自身が JavaScript™ コードを使って非同期に自動的に更新を行います (図 2)。こうすることで、ユーザーはページ全体をリロードすることなく、リッチな UI (user interface) と対話動作を行うことができます。サーバーが最初のページをブラウザーに送信すると、ブラウザーはサーバーに対してコールバックをして、更新されたコンテンツを要求します。非同期 JavaScript コードの呼び出しでは、多くの場合 XML を使ってデータをエンコードしますが、XML 以外にも、JSON (JavaScript Object Notation) や HTML、区切りテキストなど、他のデータ・フォーマットも一般的に使われます。
図 2. Ajax による対話型のデータ表示

Ajax マッシュアップは混成 Web アプリケーションです。このアプリケーションは、複数ソースから非同期に取得するコンテンツを使って自動的に更新を行うリッチな UI を、Ajax の方法を使って表示します。サーバーが最初のページをブラウザーに送信すると、ブラウザーは更新されたコンテンツを取得するための呼び出しを行います。これらの呼び出しは、ブラウザーからサードパーティーのソースに対して直接行われるか、あるいはサードパーティーのコンテンツのプロキシーとして動作する、送信元のサーバーに対して行われます。
強引な使い方
現在のブラウザー環境を構成する要素が設計された当時は、誰も Ajax マッシュアップなど想定していませんでした。ブラウザーにも、HTTP (Hypertext Transfer Protocol) にも、あるいは HTML や XHTML にも、ブラウザーが複数のソースからセキュアかつ確実に、非同期でコンテンツを取得するという動作を明確に考慮して設計された機能は何も組み込まれていませんでした。W3C (World Wide Web Consortium) の HTTP 仕様の機能の一部 (例えば DOM (Document Object Model) Level 3 Load and Save Specification など) はマッシュアップに使われていたかもしれませんが、大部分のブラウザーでは完全には実装されていないか、あるいはまったく実装されていませんでした。
DHTML (Dynamic HTML) は、当初は動的に取得されたコンテンツと組み合わせて使われることはありませんでした。動的 Web ページの表示要素とデータ要素は両方とも、それらを操作するためのスクリプトと一緒に送信されました。スクリプトは文書オブジェクトを表示したり、隠したり、移動したり、作成したり、破棄したりして動的効果を作成しますが、サーバーからのデータがさらに必要な場合には、そのページは新しいページと置き換えられました。つまりデータのフローはページのリロードと同期していました。
そのため、現在私たちがマッシュアップと呼ぶ種類の混成 Web アプリケーションを作成しようとする場合には、入手可能な技術の中から要求に合いそうなものを見つけ、強引に拡張する必要がありました。そして、ブラウザーがページをリロードせずにコンテンツを取得するための方法として、2 つの方法が採用されました。つまり外部トランスポート機構を組み込む方法と、ブラウザー独自のオブジェクトを使ってトランスポートを行わせる方法です。
外部からの支援
初期のソリューションは、Microsoft® の Remote Scripting を使う方法です。この方法は、サーバー・サイド・コンポーネントと XML フォーマットのメッセージを交換する Java™ アプレットを使います。しかしこの方法は、ベンダーからの反対や JVM (Java Virtual Machine) とセキュリティー・モデルの違いなどから、すぐに困難になりました。
その後 Microsoft は XHR (XMLHttpRequest) オブジェクトを作成しました。これを設計した人達は、このオブジェクトは Microsoft の OWA (Outlook® Web Access) でのみ使われるものと想定していました。このオブジェクトは、最初は Windows Internet Explorer® のユーザーしか利用することができず、そのため何年も後になって Mozilla と Safari に採用されるまで、広く使われることはありませんでした。このオブジェクトは元々、外部 Microsoft ActiveX® オブジェクトでしたが、現在ではブラウザー内のネイティブ・オブジェクトです。XHR オブジェクトはその名前に反して、妥当な XML に限らず、任意のフォーマットでデータを転送することができます。
多くの開発者は、サーバーと通信する組み込み可能なコンポーネントを作成する場合、Macromedia Flash の XML 通信機能を使っています。XMLSocket オブジェクトと flex.net.socket オブジェクトも XHR と似た機能を持っていますが、これらのオブジェクトは他にも通信制御機能と XML 構文解析機能を持っています。
内部機能による方法
外部トランスポート機構にはさまざまな問題や依存関係が付随するため、インターネット開発コミュニティーはブラウザー固有のリモート呼び出し方法を発見し、開発するために協力してきました。そうした方法としては次のようなものがあります。
- 隠し要素 iframe を使って外部コンテンツをロードする方法。
コンテンツをロードしたら DOM を使って iframe にアクセスし、iframe がロードした文書からコンテンツを抽出します。任意のパラメーターを URL の querystring で指定することができ、あるいはサービスにポストするフォームを、iframe をターゲットとして動的に作成することができます。この方法は、現在のブラウザーでも古いブラウザーでも、広範囲な種類のブラウザーで使用することができます。 - img 要素を使ってコンテンツに対するリクエストを送信する方法。
サーバーは URL の querystring のパラメーターを使って動作を行い、そしてクッキーの中にエンコードされたコンテンツを返します。この方法は、容易に通信できるデータの量が限定されます。これは querystring もクッキーもサイズが限定されているためです。 - 現在のページの DOM の中にスクリプト要素を動的に作成する方法。
サーバーが提供するコードは、ロードされると即座に実行されます。サーバーは URL の querystring のパラメーターを使います。
こうしたツールや方法に関する詳細については、「参考文献」を参照してください。
制限を破る
非同期にコンテンツを取得するために利用可能な方法の大部分は、そのセキュリティーを JavaScript のセキュリティー・モデルから継承します。これによってスクリプトは、そのスクリプトが含まれているページがあるサーバーから送られる要素のみと対話動作を行います。これが、同一生成元ポリシー (Same Origin Policy) であり、すべてのブラウザーはこれを実装しています。
Web ページがサードパーティーのソースからコンテンツを取得するためには、同一生成元ポリシーを回避する必要があります。同一生成元ポリシーによって制限されずに一般的に使われる例外が、<script> タグを使う方法です。この方法では、ページの DOM に <script> 要素を追加すると、<script> 要素はこの要素の src 属性で指定される URL で見つかるコードをロードして実行します。
<script> タグを使って複数のサイトにあるスクリプトを実行する方法は、関係するすべてのサイトの間に高度の信頼関係があることを前提としています。なぜなら、そうしたスクリプトはすべて同じ実行コンテキストと同じセキュリティー・コンテキストで実行され、従って他のサイトからの情報やクッキーにアクセスできてしまう可能性があるためです。
セキュリティーかスケーラビリティーか、両方は実現できません
Ajax マッシュアップを実現するために現在広く使われている回避策には、どれも代償を伴います。ブラウザー用に当初意図された制限を強引に広げると、アプリケーション全体としての動作の、他の側面が影響を受けます。通常は、アプリケーションがセキュアでなくなるか、あるいはスケーラブルでなくなります。
確かにセキュアですが、スケーラブルでしょうか
ブラウザーの同一生成元ポリシーに制限される場合、アプリケーションをホストする同じサーバーは、サードパーティーのコンテンツを取得してクライアントに送信する動作を行います。サーバーは、通常のサーバー機能の他に、サードパーティーのサービスへのクライアントとして動作します。
サーバーをすべてのクライアント・トランザクション用のプロキシーとして使うということは、多数のユーザーを処理するために過度の負荷がサーバーにかかることを意味します。この方法を使うアプリケーションは、要求負荷を処理するために、複数の協調サーバー群を使ってサーバー・サイドがスケーラブルになるように設計されている必要があります。
確かにスケーラブルですが、脆弱ではありませんか
<script> タグを使って同一生成元ポリシーを回避する方法では、クライアントはサードパーティーからコンテンツを取得することができます。この方法では、追加される各クライアントが、それぞれ独自にコンテンツ収集動作を行うため、スケーラビリティーに関するサーバーのボトルネックがなくなります。
ただし <script> タグによりスケーラビリティーを向上する方法の利点は、同一生成元ポリシーのセキュリティー・モデルを外れるという代償を伴い、潜在的な攻撃に対して次のような脆弱性が発生します。
- サイトにまたがってクッキーにアクセスできてしまう: あるサイトのスクリプトが別のサイトのクッキーにアクセスできてしまいます。
- 取得されたコードの実行前に安全性を検証する機会がない: コードはロードされると即座に実行されていまいます。
潜在的なソリューション
上記の説明から明らかなように、マッシュアップのために現在ブラウザーが提供しているツールは、スケーラブルかつセキュアなアプリケーションを作成するためには不十分です。開発者は、現在、そして今後長期にわたり有効なソリューションを見つけなければなりません。
当面のソリューション
最近開発されたコンテンツ取得方法では、ページのスクリプトと、隠れた iframe との間で、そのページの src URL のフラグメント識別子 (# 記号の後にある、URL の一部) を使って通信を行います。親ページにあるスクリプトと、埋め込まれた iframe は、それぞれ送信元は別ですが、お互いのフラグメント識別子を設定します。このようにして合意された通信プロトコルは、このフラグメント識別子の変化をチェックするルーチンを JavaScript タイマーが周期的に起動することで、スクリプト同士の間で維持されます。
スクリプトはお互いのアドレスを認識している必要があり、両者は協調してプロトコルに合意する必要があるため、信頼関係が保証されます。サーバーとの対話動作は各コンポーネントのローカル動作であり、スクリプト間の通信とは別であるため、クッキーが公開されることはありません。
このソリューションは、まだ完全ではありません (例えば、設計された動作とは異なる変則性に依存していること、またポーリングで変更を調べる方式は、変更に対応してイベントが起動される方法よりも劣っていること、など)。しかし他のどの方法よりも、ブラウザー固有でセキュア、そしてページ内動作、クロス・ドメインの通信を提供するという目標に近づいています。
注意: AOL Developer Network の開発者である James Burke は、フラグメント識別子による方式を開拓し、それを Dojo Toolkit JavaScript ライブラリーの最新リリースに組み込みました。
長期的なソリューション
ブラウザーの開発元や開発コミュニティーは現在、Ajax マッシュアップ専用にブラウザー環境の要素を変更できないか、いくつかの方法の可能性を議論しています。WHATWG (Web Hypertext Application Technology Working Group) は、その Web Applications 1.0 Working Draft のセクション 7.3 の中で、Cross Document Messaging と呼ばれる機構を提案しています。Opera ブラウザーは既にこの機能を実装しています。この仕様は、さまざまなドメインの DOM オブジェクト同士が協調して通信する方法を規定しています。この方法では、メッセージの受信者が、どのメッセージに応答するかを、メッセージのソースに応じて選択することができます。
Ian Hickson (Opera の社員でしたが、現在は Google 社員です) は、既存の XMLHttpRequest オブジェクトに対するクロス・サイトの拡張機能を提案しています。彼の提案は、リクエストを行う方法に対するいくつかの変更 (ヘッダー・コントロールの制限やアクセス制御機構など) から構成されています。
JavaScript のエバンジェリストでありアーキテクトでもある Yahoo! の Douglas Crockford は、JavaScript 言語に関する知識が最も豊富なエキスパートです。彼の個人 Web サイトや Yahoo! Developer Network では、JavaScript の高度な手法に関する彼の数多くのプレゼンテーションや記事を見ることができます。Crockford が推進している、もう 1 つのイニシアチブが JSON です。JSON は Ajax アプリケーションに広く使われているデータ交換フォーマットですが、その主な理由は JavaScript で簡単に構文解析でき、XML ほど冗長ではないためです。Crockford はこれまで、マッシュアップを認識する要素をブラウザーに組み込むための方法として、2 つの提案を行っています。
未解決の提案
この困った状況に対応するための提案が、いくつか未解決のままになっています。
- JSONRequest に関する提案: ブラウザーが新しいオブジェクトを実装する。このオブジェクトは既存の XMLHttp オブジェクトとほとんど同じように動作しますが、下記の点が変更されています。
- JSONRequest を同一生成元ポリシーから除外する。
- 最小限の HTTP ヘッダーのみを使用し、リクエスト全体としてのサイズを削減する。
- クッキーを転送しないことによって、クロスサイトのクッキーの問題を確実に回避する。
- JSONRequest は有効な JSON テキストのみを受け付ける。そのため、生の実行可能コードが送られて実行されることがなくなる。
- 通信に失敗した後、リトライ前にランダムな遅延を挿入し、一定種類の攻撃を受けにくくする。
- 各リクエストがシーケンス ID を返すようにし、非同期レスポンスを元々のリクエストと容易に関連付けられるようにする。
- 特別に二重接続をサポートすることによって、サーバーは開いている通信チャネルを使って非同期に通信を開始する。
- <module> タグに関する提案: 新しい HTML タグによって、ページをモジュールの集合に分割する。これらのモジュールは互いにセキュアでありながら、次のような方法で安全に通信することができます。
- <module> タグは (同一生成元ポリシーの例外として) サードパーティーのリソースにアクセスできる。
- ページとモジュールの間の協調した通信は、特定のインターフェースを通してのみ可能とする。モジュール同士は通信を行えず、モジュールはページとのみ通信することができます。ただしページはモジュール同士を通信させる選択をすることができます。
- JavaScript オブジェクトによる通信とは違って、通信は有効な JSON テキストのみを使って行う。 (JavaScript オブジェクトによる通信では、添付されたコードによってセキュリティー・リークを起こす可能性があります)。
- また、モジュールとページが互いに表示を妨害してセキュリティー問題を引き起こさないようにするための制限が提案されています。
- コンテンツ制限ヘッダーに関する提案: Gervase Markham はコンテンツ制限ヘッダーの仕様を提案しています。この仕様では、コンテンツの作成者が、他のサイトのコンテンツとの対話動作に関する作成者の意図を完全に表現することができます。これに準拠した実装は、ポリシーを示す文字列を含んだコンテンツ制限ヘッダーを送信します。
- W3C の ACL (Access Control List) システムに関する提案: W3C の ACL システムは、ACL ベースのシステムのモデルとして、Ajax マッシュアップで HTTP で提供されるリソースへのアクセスの制御に使用することができます。
- Cross-domain.xml に関する提案: フラッシュ・オブジェクトは、指定された URL にアクセスしようとする前に、サーバー上にある、cross-domain.xml と呼ばれるファイルを探します。このファイルは、そのサーバーが提供するサービスにアクセスするアプリケーションを、どのサイトがホストするかを指定します。多くの Web サービス・プロバイダーが既にこのファイルを実装しています。
これらの提案についての詳細は、「参考文献」を参照してください。
今後の改善に協力するために
開発者としての私達は、誰もがこうした議論の結果に影響を受けます。皆さんもこうした議論に参加することで、ブラウザーを最も柔軟かつセキュアに改善するための設計に協力することができます。それによって、堅牢でセキュア、そしてリッチな Web アプリケーションを誰もが構築できるようになります。皆さんもブラウザーの進歩を推進するブラウザー・ベンダーや組織を探し出し、そして、
- 業界の協議会やワーキング・グループに参加してください。
- ニュースグループやフォーラムでブラウザー・ベンダーやツール・ベンダーと議論してください。
- 業界のキー・プレーヤーを探し出し、彼らに参加を呼びかけてください。
そのための出発点へのリンクは、この記事の「参考文献」にあります。
ダウンロード可能なリソース
関連トピック
- developerWorks XML ゾーンでは XML のすべてを学ぶことができます。
- Alex Hopmann による、XMLHTTP の始まりの歴史、The story of XMLHTTP を見てください。
- プログラムやスクリプトが XML 文書の内容を DOM 文書の中に動的にロードし、また DOM 文書を XML 文書にシリアライズするための方法に関するW3C の仕様、DOM Level 3 Load and Save Specification を読んでください。
- Mozilla の Web サイトには、1 つのソースからロードされた文書あるいはスクリプトが別のソースからの文書プロパティーを取得したり設定したりすることを防ぐためのポリシー、同一生成元ポリシーに関する情報があります。
- 「クロスサイト・スクリプティング」(Paul Lee 著、developerWorks、2002年9月) を読んで、こうしたスクリプト問題に関して学んでください。
- 「Remote scripting using a servlet」(Erik Hatcher 著、developerWorks、2001年2月) と「Sending rich messages between client and server using asynchronous messaging」(Erik Hatcher 著、developerWorks、2001年5月) は、それぞれ標題の方法について解説しています。
- Brent Ashley によるプレゼンテーション・ノート、「Ajax Transport Layer Alternatives」が彼の Web サイトで公開されています。
- iframe とフラグメント識別子の発見に関して知るために、James Burke のオリジナル・ブログを見てください。
- フラグメント識別子によるトランスポート方法を Dojo Toolkit がどう実装しているかを知るために、Dojo Toolkit's implementation を読んでください。
- WHATWG の提案、Cross-document messaging を読んでください。
- Ian Hickson による、更新された提案、Cross-site
XMLHttpRequest
を読んでください。 - マッシュアップのセキュリティー問題に関する Douglas Crockford の提案、
JSONRequest
と<module>
タグ による方法を読んでください。 - ブラウザーが正当なスクリプトと悪意のスクリプトを区別するための、Gervase Markham による提案、Content restriction headers を読んでください。
- W3C による、動的なファイル・レベルのアクセス制御システム、ACL System について読んでください。この仕様には、ACL ストレージやクエリー機構の他、このデータのセマンティック Web での利用可能性や使い方が記述されています。
- Flash の
XMLSocket
オブジェクト と cross-domain.xml ファイルについて調べてください。XMLSocket オブジェクトとクロスドメイン・ポリシー・ファイルによって、Flash Player を実行するコンピューターと、IP アドレスあるいはドメイン名で識別される別のサーバーとが通信することができます。 - XML および関連技術において IBM 認証開発者になる方法については、IBM XML certification を参照してください。
- developerWorks の XML ゾーンは XML の技術ライブラリーとして、広範な話題を網羅した技術記事やヒント、チュートリアル、技術標準、IBM レッドブックなどを用意しています。
- developerWorks から直接ダウンロードできる IBM trial software を使って皆さんの次期開発プロジェクトを構築してください。