はじめに
信頼できない (ウェブページの) コンテンツの DOM インターフェイスをスクリプトで扱うアプリケーションや拡張機能では、扱う情報が本当に DOM API の物なのか、悪意のあるページで定義された JavaScript のプロパティやゲッタ・セッタ関数ではないかという事に注意する必要があります。Firefox 1.0.3 と Mozilla 1.7.7 では、chrome 権限を持つ JavaScript がオブジェクトの DOM プロパティやメソッドにアクセスする時に、ウェブページによって上書きされた物を取得しないことが保証されており、ウェブページが XUL アプリケーションや拡張機能を欺くのをより難しくしています。Firefox 1.5 ではより一般的な問題解決法がデフォルトで有効になっており、拡張機能は明示的にそれを脱出しなければ危険な DOM アクセスを実行できません。
chrome コードがコンテンツの DOM にアクセスするには、直接のアクセスと、XPCNativeWrapper の明示的な使用の二つしか「正しい」方法はありません。特に、よく使われる __proto__
トリックはどのバージョンでも安全ではありません (下記の「やってはいけない事の例」を参照) 。
次の表は二つの「正しい」方法のセキュリティ上の特性を要約したものです。
直接のアクセス | 明示的な XPCNativeWrapper | |
---|---|---|
Firefox 1.0.2 以前 | 危険 | 安全 |
Firefox 1.0.3 以降 (1.0.x) | プロパティの存在が保証されていれば安全 | 安全 |
Firefox 1.5 | xpcnativewrappers=yes (デフォルト) ならば安全
| 安全 |
直接のアクセス
Firefox 1.0.3 以降の 1.0.x のバージョンでのみ動くように設計されたスクリプトや、Firefox 1.5 以降で xpcnativewrappers=yes
が使われているスクリプトでは単純に次のように呼び出せます。
return contentWindow.document.title == contentWindow.getSelection();
直接のアクセスは、Firefox 1.0.3 (及びそれ以降のバージョン 1.0.x) では、オブジェクトがその IDL 宣言を通じてアクセスされるプロパティやメソッドを持っている事を保証されている限りは安全です。例えば、foo.nodeType
は foo が Node
であると確信できる限りは安全で、foo.getSelection()
は foo が window であると確信できる限りは安全です。これを正確にやるのにはこつが要る場合があります。例えば、nsIDOMNSHTMLDocument
は open()
メソッドを持っていますが、nsIDOMXULDocument
は持っていません。なので、Firefox 1.0.3 で document.open()
を使うのは安全ではありません。document
は XUL ドキュメントかもしれないからです。このような場合、オブジェクトが特定の IDL インターフェイス (この場合は nsIDOMNSHTMLDocument
) をサポートしているかどうかを判断するのに instanceof
演算子が使えます。
Firefox 1.5 では、拡張機能がマニフェストで xpcnativewrappers=no
フラグを使っていない限りは、直接のアクセスは常に安全です。このフラグがセットされていなければ、暗黙のうちに XPCNativeWrapper が使用されます。
XPCNativeWrapper の明示的な使用
var winWrapper = new XPCNativeWrapper(contentWindow, 'document', 'getSelection()'); var docWrapper = new XPCNativeWrapper(winWrapper.document, 'title'); return docWrapper.title == winWrapper.getSelection();
この例では window.document.title
を得るのに二つのラッパを使用している事に注目してください。一つのラッパは window
から document
プロパティを取得するためのもので、もう一つのラッパは document
から title
プロパティを取得するためのものです。
XPCNativeWrapper を使えば Firefox の全てのバージョンで安全になりますが、コードが読みずらくなりますし、全ての DOM オブジェクトを注意深くラッピングしなければなりません。
この構文についての更なる情報は、MozillaZine ナレッジベースの XPCNativeWrapper
の項を参照して下さい。
XPCNativeWrapper について
XPCNativeWrapper
は特権コードから安全にアクセスするためにオブジェクトをラッピングする手段です。
XPCNativeWrapper
の使用には二つの方法があります。古い方法はそれを明示的に使用する事です。新しい方法である xpcnativewrappers=yes は、Firefox 1.5 及び Deer Park のアルファとベータプレリリースから利用できます。
やってはいけない事の例
Firefox 1.0.2 以下での悪い例です。スクリプトが nodeType
ゲッタを上書きする事が出来るからです。
return targetNode.nodeType == 1;
Firefox 1.0.2 以下での悪い例です。スクリプトが getSelection
を上書きする事が出来るからです。
return contentWindow.getSelection();
全てのバージョンでの悪い例です。過去何人かの開発者がこの愚かなトリックを使っていました。古いバージョンではスクリプトが getSelection
を上書きする事が出来ます。Firefox 1.0.3 と Mozilla 1.7.7 ではこれはまったく機能しません。
return contentWindow.__proto__.getSelection.call(contentWindow);
Firefox 1.0.2 以下での悪い例です。外側のゲッタは安全ですが、スクリプトが内側のゲッタを上書きできるからです。
var winWrapper = new XPCNativeWrapper(contentWindow, 'document'); // contentWindow.document の取得は安全になったが、 // 返ってきた document から .title を取得するのは依然として安全ではない return winWrapper.document.title;
Firefox 1.5 より前のバージョンでの悪い例です。スクリプトが DOM の document.open
を持たない非 HTML ドキュメントに document.open
をセットする事が出来るからです。
return contentWindow.document.open();