window.nameによるクロスドメイン通信

随分前になるが、SitePenの人 (dojo) が書いたブログに window.nameを使ったクロスドメイン通信についてまとめられていた。

window.name Transport - Blog | SitePen

気になっていたがちゃんと読む時間がなかったので、今ごろ見てみる。抜粋して訳。

window.name による通信

The window.name transport is a new technique for secure cross-domain browser based data transfer, and can be utilized for creating secure mashups with untrusted sources. window.name is implemented in Dojo in the new dojox.io.windowName module, and it is very easy to make web services available through the window.name protocol.

window.nameによる通信はブラウザ上でのセキュアなクロスドメイン通信をおこなうための新しいテクニックで、事前の信用がない情報ソースであっても安全にマッシュアップすることができる、とのこと。dojoはすでにこの方式による通信を dojo.io.windowNameモジュールとしてライブラリの中に実装しているようだ。

window.name works by loading a cross-domain HTML file in an iframe. The HTML file then sets its window.name to the string content that should be delivered to the requester. The requester can then retrieve the window.name value as the response. The requested resource never has access to the requester’s environment (JavaScript variables, cookies, and DOM).

window.nameによる通信は、iframeの中にクロスドメインに置かれたHTMLファイルをロードさせることで行われる。ロードされたHTMLファイルが window.nameに文字列をセットし、それをリクエスト送信元に返す。リクエスト送信元は送られてきたwindow.nameをレスポンスとして取得することができる。(JSONPなどのスクリプト読み込みによるクロスドメイン通信などと違って)レスポンスコンテンツがリクエスト送信元の環境(変数、クッキーやDOMなど)にアクセスすることはできない(ため安全である)。

利点

Benefits

This technique has several advantages over other cross-domain transports:

* It is secure, JSONP is not. That is, it is as secure as other frame based secure transports like fragment identifier messaging (FIM), and Subspace. (I)Frames also have their own security issues because frames can change other frames locations, but that is quite a different security exploit, and generally far less serious.
* It is much faster than FIM, because it doesn’t have to deal with small packet size of a fragment identifier, and it doesn’t have as many “machine gun” sound effects on IE. It is also faster than Subspace. Subspace requires two iframes and two local HTML files to be loaded to do a request. window.name only requires one iframe and one local file.
* It is simpler and more secure than Subspace and FIM. FIM is somewhat complicated, and Subspace is very complicated. Subspace also has a number of extra restrictions and setup requirements, like declaring all of the target hosts in advance and having DNS entries for a number of different particular hosts. window.name is very simple and easy to use.
* It does not require any plugins (like Flash) or alternate technologies (like Java).

  • 安全である。一方、JSONPはそうでない*1。同じくframeを使った通信方法であるFragment Identifier Messaging (FIM) と同等といえる。
  • パケットに分割する必要がないため、FIMよりも速い。
  • SubspaceやFIMのような方法よりシンプルでかつ安全である。FIMも複雑だけど、Subspace はかなり複雑だし、事前の環境制約も多い。
  • FlashようなプラグインややJavaのような代替技術は要りません。

どのようにして動くのか?

How does it work?

Of course you can use the new windowName module without understanding how it works, but since this is a tool for protecting against miscreant web services, you may wish to understand how it provides protection. name is a property of the global/window object in the browser environment, and the value of the name property remains the same as new pages are navigated for the frame. By loading a resource in an iframe where the target page will set the name property for its frame, this name property value can be retrieved to access the information sent by the web service.

ブラウザ環境におけるグローバル/ウィンドウオブジェクトのプロパティ"name"は、ページ遷移してもそのまま残るという特徴がある。そこでiframeの中にwindow.nameに値をセットするHTMLファイルを読み込んでやることで、(クロスドメインの)Webサービスからデータを取得することが可能になる。

The name property is only accessible for frames that are in the same domain. This means that Dojo must navigate the frame back to the origin domain after the remote web service page has been loaded, in order to access the name property. This same-origin policy also protects against other frames from accessing the name property while Dojo is retrieving the value. Once the name property is retrieved, the frame is destroyed.

ただし、nameプロパティにアクセスできるのは同じドメインのフレームだけなので、ページがロードされたらフレームを一度もとのドメインに戻してやる必要がある。データのやり取りの最中は(異なるドメインに存在している)他のフレームからwindow.nameへのアクセスは遮断されており、そしてデータ通信が終わればframeは破棄される。

At the top level, the name property is not secure, any information put in the name property is available for all subsequent pages. However, the windowName module always loads resources in an iframe. The iframe is destroyed once the data is retrieved, or when you navigate to a new page at the top level, so other pages never have access to the window.name property.

トップレベルのウィンドウでwindow.nameに設定した値は遷移したどのページからもアクセスできてしまうけれども、iframeを使っていればデータが取得されたらすぐ破棄することができるし、ページ遷移してしまえば次のページからもうアクセスは不可能である。

The principle vector of attack is for other frames to attempt to access the loading frame and navigate that frame to their own domain in order to access the name property (using the same technique that Dojo does).

However, navigating frames that are not child or parent frames is not permitted in most browsers, and therefore the third party frames are blocked from this action by the browser. Only the main frame that is loading the resources can access this information. Unfortunately, Firefox 2 does not block this action. Consequently, the windowName module uses a set of three nested frames, where 1st frame blocks all frame traversal to the 2nd frame using dynamically installed getters that return null. This means that third party frames can never traverse the frames to get a reference to the 2nd or 3rd frames, and consequently can never induce navigation of the target frame (the 3rd frame) in order to access the name property. Same-origin security prevents the third party frame from removing the installed getter that protects access to the inner frames as well. These measures protect against attacks and ensure that data can be delivered securely.

攻撃の方法としては(悪意あるコードがページの中の別フレーム中に読み込まれていたとして)window.name通信のために使っているframeを(window.nameに有益な情報がセットされタイミングにあわせて)自分のドメインのURLに書き換えてしまう、ということが考えうる。

このようなアクセスはほとんどのブラウザのセキュリティポリシーで許可されていないが、Firefox 2ではこれをブロックしないようだ。このため、dojoでは間に1つframeを挟み、そこでgetterを定義してさらにinnerのframeに第3者がアクセスすることを禁じるようにしている。

      • -

以上。実装の詳細については後ほど自分でまとめる予定。ちょっとやってみた感じでは、JSONPほどではないが、主張の通りFIMよりかなり簡単ではなかろうかと思われる。


ちなみにdojoJSONPにしろfragment identifierにしろ、こういうhackをライブラリ化するのが得意のようです。
dojo toolkitのScriptSrcIO - snippets from shinichitomita’s journal
dojoのIFrameProxyでクロスドメインでのXML取得 - snippets from shinichitomita’s journal


その他、window.nameに関して。
サーバーサイド技術を使わないクロスドメイン通信補足 - os0x.blog
window.name - Enjoy*Study


(追記)
自分でwindow.nameの通信を実装してみた。
window.nameによるクロスドメインXMLHttpRequestを実装してみる - snippets from shinichitomita’s journal

*1:データソース提供者への事前の信頼を必要とする、という意味で