Safely accessing content DOM from chrome

Our volunteers haven't translated this article into Italiano yet. Join us and help get the job done!

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 2 and newer

Advances in Firefox technology allow safe control over web pages with some limitations. In the following "win" refers to a web page DOM window object in an extension function, but the rules apply to any property deeper in the DOM.

  • Read access: access to  win objects is safe. calling win functions is prevented.
  • Write access: you can set properties on win, but the wrappers will prevent these changes from being seen in the page (silent failure). 
  • win.wrappedJSObject:  You can delete properties and add properties that are strings and numbers by using win.wrappedJSObject. Do not add objects created in your extension: this is currently unsafe (see bug 464527). This includes adding function objects.  For this reason, strictly limit the scope of operations on wrappedJSObject, so you don't pass it in to a method and later operate on it unsafely.

Old versions of Firefox

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 formerly 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.

Note: xpcnativewrappers=no is no longer supported starting in Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1). More information.

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 in Firefox 1.5 and later.

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();

Document Tags and Contributors

Last updated by: Sheppy,