Safely accessing content DOM from chrome

はじめに

信頼できない (ウェブページの) コンテンツの 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 であると確信できる限りは安全です。これを正確にやるのにはこつが要る場合があります。例えば、nsIDOMNSHTMLDocumentopen() メソッドを持っていますが、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();

ドキュメントのタグと貢献者

 このページの貢献者: Mgjbot, Shoot
 最終更新者: Mgjbot,