The upcoming Dojo 1.2 release features a new comprehensive framework for building secure mashups with the dojox.secure project. This new project includes all the components necessary for safely loading untrusted code, advertisements, content, and widgets from other domains, validating that it is safe to execute, and providing a sandboxed environment and controlled subset of the DOM to interact with. Using traditional means, loading scripts from other domains is a great security vulnerability, every script has full access to the JavaScript environment and DOM of the source page. The alternate approach has been to use iframes, which greatly limits UI integration and programmatic interaction. With dojox.secure, untrusted scripts and widgets can be safely loaded directly into a web page with fine grained sandboxing of their capabilities, while still allowing them to access a controlled subset of the DOM and JavaScript environment.

Cross-Site Loading

The first step in using dojox.secure for loading third-party content is to define a transport mechanism for loading the resources from the target domain. The new XHR Plugin Registry is designed to provide a simple mechanism for defining what cross-domain loading mechanisms are available with the target server, and Dojo supports a comprehensive set of cross-domain loading tools. Most servers currently do not yet support any cross-domain loading mechanism, but Dojo includes transports for those servers lacking cross-domain support. The window.name transport can be used for servers that support the window.name protocol, and native cross-site XHR can be used when browsers add support (this should be available in next major release of the all major browsers). To define that resources should be loaded from siteA.com with the window.name protocol you can register a server:

dojox.io.xhrWindowNamePlugin("http://siteA.com");

However, since most servers do not support these protocols yet, using a simple proxy will often need to be used as the default loading mechansim for dojox.secure. To use a proxy, you simply need to create a very simple request handler that can take a URL, retrieve the resource and return it. You can then register the proxy as the cross-site resource loader:

dojox.io.xhrPlugins.addProxy("/proxy?url=");

Since the window.name transport can be used on all major web browsers, once a server supports the window.name protocol, it is no longer necessary to use a proxy. Note, that you should not attempt to use JSONP for cross-site loading for dojox.secure, because while it works, it is inherently insecure.

Sandboxing the Widget

secure-sandbox.png

Once you define the resource loading, creating a sandbox for a script or an HTML snippet is very simple. You choose a DOM element that would be the parent for the widget and load the script using dojox.secure sandbox API.

This is the DOM area that the widget can access

And then create a sandbox:

dojo.require("dojox.secure.sandbox");
var mySandbox = dojox.secure.sandbox(dojo.byId("sandbox"));

Once a sandbox instance is created, you can load and execute JavaScript files and HTML snippets into the sandbox:

mySandbox.loadJS("http://siteA.com/widget.js");

The loadJS function will load the file from the provided URL, validate that it is safe JavaScript, and execute it within the sandbox. The executed script will be limited to only accessing the sandboxed JavaScript environment and the sandbox element and any children nodes or HTML of that element.

You can also load HTML snippet based widgets into the sandbox:

mySandbox.loadHTML("http://siteA.com/widget.html");

The loadHTML function will load the file from the given URL and insert the HTML from the file into the target sandbox element. All scripts within the HTML will also be properly sandboxed as well.

Because the sandbox is actually in the same JavaScript environment, interaction is very flexible. If a script returns a valid JavaScript value when evaluated, this value is returned from loadJS and data and messages can easily be passed back and forth to a sandboxed script through that value/object.

var widgetInstance = mySandbox.loadJS("http://siteA.com/widget.js");
// then call some method on the widget object
widgetInstance.sendGreeting("hello");
// then register to listen for some event
dojo.connect(widgetInstance,"onSomeEvent", function(val){ ... }); 

Of course, the parent environment can still freely interact with the sandboxed element and any other DOM nodes that the sandboxed content creates.

Building Widgets for dojox.secure

dojox.secure attempts to provide as many of the standard native capabilities of the browser environment and JavaScript language as possible. However, in order to maintain safe, secure, lightweight, high-performance design and avoid massive compilation techniques, there are a number of features that are not available within the dojox.secure sandbox environment. Many of these restrictions are mitigated by a rich set of library functions, but we will first look at the restrictions. dojox.secure is based on the ADsafe dialect of JavaScript, with some minor differences, so the following language features are disabled:

  • Use of eval, with, ==, !=, and the subscript operator [] are not allowed.
  • The this keyword can not used outside of a class definition
  • Global variables from the parent environment are not accessible
  • These properties may not be used: apply, arguments, call, callee, caller, constructor, eval, prototype,
    this, unwatch, valueOf, watch, and anything beginning or ending with __.

dojox.secure also prevents the following DOM features:

  • Relational traversal though parentNode, firstSibling, nextSibling, parentElement, etc. properties are not allowed. You can still use DOM methods, innerHTML, and style attributes
  • CSS does not allow expression, behavior, javascript:, binding, or @import
  • link tags are not allowed
  • Inline JavaScript within event handler attributes is not allowed.

dojox.secure uses a combination of JavaScript validation and a DOM facade to enforce these constraints. Attempts to use any of the disabled features will fail (usually with an exception, although sometimes silently).

dojox.secure Environment Capabilites

dojox.secure does provide a number of features to not only mitigate the security restrictions, but provide a comprehensive set of features for building widgets. A sandboxed script can access the sandboxed element with the element variable. Node creation and searching can be done with the provided sandboxed document variable. Most of the top level JavaScript functions are available like encodeURIComponent, setTimeout, etc. There are also top level functions get, set, and forEach for iterating and accessing properties by element since the [] operator is restricted, and dojox.secure provides a class constructor mechanism which supports the this keyword within methods. Most of the rich library functionality comes from corresponding functions in Dojo, that are accessible as top level functions (there is no need for namespaces because there is no access to the global object).

dojox.secure defines a subset of the Dojo base library that can be accessed from sandboxed scripts. This includes functions like query, mixin, connect, fromJson, and more. A more detailed description of the API available from within the sandbox, as well as a demo page for testing sandboxed scripts and HTML is available.

An example of a simple widget that can be created for use with dojox.secure:

This is sandboxed HTML with a script.

These features allow widgets to be easily built and utilized by web applications from other domains. The API is intentionally designed such that other libraries could implement it as well. This means that you can write a widget for use with a dojox.secure client, but it can also be safely loaded and executed by other client implementations as well.

Conclusion

dojox.secure is a full framework for loading and executing untrusted code, advertisements, and widgets, and provides a powerful yet secure environment for widgets to interact within. Current mashup technology that utilizes direct script loading is inherently unsafe, but with dojox.secure, it is very simple to load widgets and create mashups with proper security enforced while maintaining excellent performance. dojox.secure also provides an excellent platform for building widgets, such that clients can consume your widgets without compromising security.