Safely accessing content DOM from chrome

  • Revision slug: Safely_accessing_content_DOM_from_chrome
  • Revision title: Safely accessing content DOM from chrome
  • Revision id: 98920
  • Created:
  • Creator: Mgjbot
  • Is current revision? No
  • Comment robot Modifying: [[pl:Bezpieczny dostęp do składników DOM z poziomu chrome]] <<langbot>>

Revision Content

Introduction

Applications and extensions that script DOM interfaces on untrusted (web page) content need to be careful that the information that they use is really coming from the DOM API and not from JavaScript properties, getter functions, and setter functions defined by a malicious page. Firefox 1.0.3 and Mozilla 1.7.7 make it harder for web pages to trick XUL applications and extensions by ensuring that when chrome JavaScript accesses a DOM property or method on an object, it will get the DOM property or method rather than the Web page's override. Firefox 1.5 has a more general solution that's enabled by default; extensions have to explicitly opt out to perform insecure DOM access.

There are only two "correct" ways for chrome code to access the content's DOM: direct access, and explicit use of XPCNativeWrapper. In particular, the commonly used __proto__ trick is not secure in any version (see "Examples of what NOT to do" below).

The following table summarizes the security properties of the two "correct" methods:

Direct access Explicit XPCNativeWrapper
Firefox 1.0.2 and below insecure secure
Firefox 1.0.3 and newer (1.0.x) secure when property guaranteed to exist secure
Firefox 1.5 secure with xpcnativewrappers=yes (which is the default) secure

Direct access

Scripts designed to run only in Firefox 1.0.3 and later 1.0.x versions or that use xpcnativewrappers=yes in Firefox 1.5 or later may simply call:

return contentWindow.document.title == contentWindow.getSelection();

Direct access is secure in Firefox 1.0.3 (and later 1.0.x versions) as long as the object is guaranteed to have the property or method that is accessed through its IDL declaration. For example, foo.nodeType is secure as long as you are sure foo is a Node, and foo.getSelection() is secure as long as you are sure foo is a window. Getting this right can be tricky -- for example, nsIDOMNSHTMLDocument has an open() method, but nsIDOMXULDocument does not, so using document.open() is NOT safe in Firefox 1.0.3, since document might be a XUL document. In such cases, you can use the instanceof operator to determine whether you have an object that supports a given IDL interface (nsIDOMNSHTMLDocument in this case).

In Firefox 1.5, direct access is always secure unless your extension uses the xpcnativewrappers=no flag in its manifest. If that flag is not set, then use of XPCNativeWrapper is implicit.

Explicit use of XPCNativeWrapper

var winWrapper = new XPCNativeWrapper(contentWindow,
                                      'document', 'getSelection()');
var docWrapper = new XPCNativeWrapper(winWrapper.document, 'title');
return docWrapper.title == winWrapper.getSelection();

Note that this example uses two wrappers to get window.document.title, one wrapper for getting the document property from the window, and one wrapper for getting the title property from the document.

Use of XPCNativeWrapper is secure in all versions of Firefox, but it makes code harder to read and you have to be careful to wrap every DOM object.

For more information on this syntax, see the entry for XPCNativeWrapper at the MozillaZine KnowledgeBase.

About XPCNativeWrapper

XPCNativeWrapper is a way to wrap up an object so that it's safe to access from privileged code.

There are two ways to use XPCNativeWrapper. The old way is to use it explicitly. The new way, xpcnativewrappers=yes, is available starting with Firefox 1.5 and its Deer Park alpha and beta pre-releases.

Examples of what NOT to do

BAD in Firefox 1.0.2 and below, since script can override nodeType getter:

return targetNode.nodeType == 1;

BAD in Firefox 1.0.2 and below, since script can override getSelection:

return contentWindow.getSelection();

BAD in all versions. Some developers have, in the past, used this ill-advised trick. Script can override getSelection in older versions and this doesn't work at all in Firefox 1.0.3 and Mozilla 1.7.7:

return contentWindow.__proto__.getSelection.call(contentWindow);

BAD in Firefox 1.0.2 and below, since script can override inner getter even though outer one is safe:

var winWrapper = new XPCNativeWrapper(contentWindow, 'document');
// getting contentWindow.document is now safe, but getting .title off
// the returned document is still not safe.
return winWrapper.document.title;

BAD in versions before Firefox 1.5, since script can set document.open for non-HTML documents, which don't have a DOM document.open:

return contentWindow.document.open();


{{ languages( { "fr": "fr/Acc\u00e8s_s\u00e9curis\u00e9_au_contenu_DOM_depuis_le_chrome", "ja": "ja/Safely_accessing_content_DOM_from_chrome", "pl": "pl/Bezpieczny_dost\u0119p_do_sk\u0142adnik\u00f3w_DOM_z_poziomu_chrome" } ) }}

Revision Source

<p>
</p>
<h3 name="Introduction"> Introduction </h3>
<p>Applications and extensions that script DOM interfaces on untrusted (web page) content need to be careful that the information that they use is really coming from the DOM API and not from JavaScript properties, getter functions, and setter functions defined by a malicious page. Firefox 1.0.3 and Mozilla 1.7.7 make it harder for web pages to trick XUL applications and extensions by ensuring that when chrome JavaScript accesses a DOM property or method on an object, it will get the DOM property or method rather than the Web page's override. <a href="en/Firefox_1.5">Firefox 1.5</a> has a more general solution that's enabled by default; extensions have to explicitly opt out to perform insecure DOM access.
</p><p>There are only two "correct" ways for chrome code to access the content's DOM: direct access, and explicit use of <a href="#About_XPCNativeWrapper">XPCNativeWrapper</a>. In particular, the commonly used <code>__proto__</code> trick is not secure in any version (see "Examples of what NOT to do" below).
</p><p>The following table summarizes the security properties of the two "correct" methods:
</p>
<table border="1">
<tbody><tr>
<th>
</th><th> Direct access
</th><th> Explicit <a href="#About_XPCNativeWrapper">XPCNativeWrapper</a>
</th></tr>
<tr>
<th> Firefox 1.0.2 and below
</th><td> insecure
</td><td> secure
</td></tr>
<tr>
<th> Firefox 1.0.3 and newer (1.0.x)
</th><td> secure when property guaranteed to exist
</td><td> secure
</td></tr>
<tr>
<th> Firefox 1.5
</th><td> secure with <code>xpcnativewrappers=yes</code> (which is the default)
</td><td> secure
</td></tr></tbody></table>
<h3 name="Direct_access"> Direct access </h3>
<p>Scripts designed to run only in Firefox 1.0.3 and later 1.0.x versions or that use <code>xpcnativewrappers=yes</code> in Firefox 1.5 or later may simply call:
</p>
<pre class="eval">return contentWindow.document.title == contentWindow.getSelection();
</pre>
<p>Direct access is secure in Firefox 1.0.3 (and later 1.0.x versions) as long as the object is guaranteed to have the property or method that is accessed through its IDL declaration. For example, <code>foo.nodeType</code> is secure as long as you are sure foo is a <code>Node</code>, and <code>foo.getSelection()</code> is secure as long as you are sure foo is a window. Getting this right can be tricky -- for example, <code>nsIDOMNSHTMLDocument</code> has an <code>open()</code> method, but <code>nsIDOMXULDocument</code> does not, so using <code>document.open()</code> is NOT safe in Firefox 1.0.3, since <code>document</code> might be a XUL document. In such cases, you can use the <code>instanceof</code> operator to determine whether you have an object that supports a given IDL interface (<code>nsIDOMNSHTMLDocument</code> in this case).
</p><p>In Firefox 1.5, direct access is always secure unless your extension uses the <code>xpcnativewrappers=no</code> flag in <a href="en/Chrome_Registration">its manifest</a>. If that flag is not set, then use of <a href="#About_XPCNativeWrapper">XPCNativeWrapper</a> is implicit.
</p>
<h3 name="Explicit_use_of_XPCNativeWrapper"> Explicit use of <a href="#About_XPCNativeWrapper">XPCNativeWrapper</a> </h3>
<pre class="eval">var winWrapper = new XPCNativeWrapper(contentWindow,
                                      'document', 'getSelection()');
var docWrapper = new XPCNativeWrapper(winWrapper.document, 'title');
return docWrapper.title == winWrapper.getSelection();
</pre>
<p>Note that this example uses <em>two</em> wrappers to get <code>window.document.title</code>, one wrapper for getting the <code>document</code> property from the <code>window</code>, and one wrapper for getting the <code>title</code> property from the <code>document</code>.
</p><p>Use of XPCNativeWrapper is secure in all versions of Firefox, but it makes code harder to read and you have to be careful to wrap every DOM object.
</p><p>For more information on this syntax, see <a class="external" href="http://kb.mozillazine.org/XPCNativeWrapper">the entry for <code>XPCNativeWrapper</code> at the MozillaZine KnowledgeBase</a>.
</p>
<h3 name="About_XPCNativeWrapper"> About XPCNativeWrapper </h3>
<p><code><a href="en/XPCNativeWrapper">XPCNativeWrapper</a></code> is a way to wrap up an object so that it's safe to access from privileged code.
</p><p>There are two ways to use <code>XPCNativeWrapper</code>. The old way is to use it explicitly. The new way, xpcnativewrappers=yes, is available starting with <a href="en/Firefox_1.5">Firefox 1.5</a> and its Deer Park alpha and beta pre-releases.
</p>
<h3 name="Examples_of_what_NOT_to_do"> Examples of what NOT to do </h3>
<p>BAD in Firefox 1.0.2 and below, since script can override <code>nodeType</code> getter:
</p>
<pre class="eval">return targetNode.nodeType == 1;
</pre>
<p>BAD in Firefox 1.0.2 and below, since script can override <code>getSelection</code>:
</p>
<pre class="eval">return contentWindow.getSelection();
</pre>
<p>BAD in <em>all</em> versions. Some developers have, in the past, used this ill-advised trick. Script can override <code>getSelection</code> in older versions <em>and</em> this doesn't work at all in Firefox 1.0.3 and Mozilla 1.7.7:
</p>
<pre class="eval">return contentWindow.__proto__.getSelection.call(contentWindow);
</pre>
<p>BAD in Firefox 1.0.2 and below, since script can override inner getter even though outer one is safe:
</p>
<pre class="eval">var winWrapper = new XPCNativeWrapper(contentWindow, 'document');
// getting contentWindow.document is now safe, but getting .title off
// the returned document is still not safe.
return winWrapper.document.title;
</pre>
<p>BAD in versions before Firefox 1.5, since script can set <code>document.open</code> for non-HTML documents, which don't have a DOM <code>document.open</code>:
</p>
<pre class="eval">return contentWindow.document.open();
</pre>
<p><br>
</p>
<div class="noinclude">
</div>
{{ languages( { "fr": "fr/Acc\u00e8s_s\u00e9curis\u00e9_au_contenu_DOM_depuis_le_chrome", "ja": "ja/Safely_accessing_content_DOM_from_chrome", "pl": "pl/Bezpieczny_dost\u0119p_do_sk\u0142adnik\u00f3w_DOM_z_poziomu_chrome" } ) }}
Revert to this revision