Virtual Machine: Policy Engine

The Policy Engine is an extensive set of definitions that define the security rules associated with the executing script. This document provides an introduction to the underlying system. We plan to release more extensive documentation explaining the underlying system as well as explanations on how the rule system augments the browser to provide full isolation.

Interception

The Web Sandbox secures JavaScript by intercepting all calls and executing them against a policy-based system. Once the virtualized code is transformed, it is loaded and executed within the context of the sandbox. For applying the policy-based system, the sandbox associates policies with the transformed virtualizable JavaScript. Each policy contains a set of rules defining the security permissions for each invocation, and each rule examines the context of the invocation to either deny, allow, or augment the execution

Policies

Policies typically encapsulate a set of capabilities. Without a policy, no code within the Sandbox will execute. The Sandbox provides four default capabilities:

Core Javascript
The Core JavaScript capability provides isolated support for JavaScript semantics. This includes support for the primitive types, the prototype chain, the built-in methods, and isolation for a private namespace.
Core DOM
The Core DOM capability provides support for the core W3C DOM API. This provides presentation isolation and normalized browser support for standards-based APIs. This capability extends the Core JavaScript capability.
Extended DOM
The Extended DOM capability provides support for useful extensions that are not apart of the W3C DOM. Eventually, any non-standard definitions included in the Core DOM capability will be moved here. However, as you review the capabilities, you will discover this work is still in progress and some APIs may be misclassified. This capability extends the Core DOM capability.
Gadgets
The Gadgets capability provides content transclusion for embedding an HTML document within the surrounding page. This capability emulates the IFrame programming model for your content. The Web Sandbox sample container page uses this capability. This capability extends the Extended COM capability.

This decomposition of core capabilities makes it easier for a host to compose an appropriate permissions model. If you want extensions to have the ability to execute JavaScript against a specific API without access to the presentation layer, you would build a new capability that extends Core JavaScript. If you want to support the isolation of an external script, you would apply the Core or Extended DOM capability.

What is in a Policy?

Policies associates a specific object type with a set of rules. The Sandbox engine enables dynamic typing of all objects in the system. Except for the built-in primitives (Strings, Numbers, Dates, etc.) and the code's global object, all other types are established dynamically at run-time via an appropriate rule. This is accomplished by ensuring that all return values, whether via a property or invocation, are typed. These types are used to establish an association with the appropriate rule. Policies are defined via a JSON-based object. Below is an example of how the rule system types the document property:

// Using the Core DOM Policy
//    On the __global__ type.  __global__ is a built-in default type 
//     representing the isolated global namespace
//    The property getter (g) for the document member
//    Returns the property typed as "HTMLDocument"
$Policy.CoreDOM.__global__.g.document = $Rule.Reference("HTMLDocument");

This type is now associated with the returned document object. If a developer invokes a member on the returned document, its rule will be looked up via the HTMLDocument type in the underlying policy. For example, if the developer attempts to retrieve the document's body property, the following rule will be applied:

// On the HTMLDocument type
// The property getter (g) for the body member
// Returns theproperty typed as "HTMLBody"
$Policy.CoreDOM.HTMLDocument.g.body = $Rule.Reference("HTMLBody");

The Policy system provides a large number of built-in default rules that can be reused. Below are a few examples:

RuleExplanation
$Rule.DenyDenies access to the operation. This is the default if no rule is specified.
$Rule.AllowPermits access to the operation without restriction.
$Rule.Reference(type)Permits access to the member. The return is typed as specified.
$Rule.ScopePermits access to the DOM Node member only if the DOM node is within your isolated sub-tree.
$Rule.ReferenceElementRule applied to all members that return a DOM Element. This automatically types the DOM element. For example, the TABLE element is typed TABLEElement when accessed.
$Rule.EventRule applied to all event properties. This provides isolated setters/getters for any event-based property.
$Rule.Chain(rule1,rule2,...)Allows multiple rules to be easily chained. For example, $Rule.Chain($Rule.Scope,$Rule.ReferenceElement) will permit access to the element-based member only if within the scope. If accessible the member will then be appropriate typed.
$Rule.Wrap(type)Wrap is a special version of $Rule.Reference. The type system works by extending the object with a hidden type property. Some objects do not support adding these custom properties. In these cases, we can synthesize an object that contains the type and a reference to the real object. The Wrap rule supplies this functionality. This is performed selectively since wrapping incurs greater performance penalties and creates object equivelency challenges.

There are many more built-in rules that can be used. We will be providing more documentation including examples in the near future. The purpose of these built-ins can often be determined by examining their use in context so feel free to review the sandbox script.

Extending Policies

Policies can extend other policies. When this occurs, the ordering of the extensions matters. If a rule is specified for a member in an extension it is not past up the chain. If a rule for a member is not defined, then the upstream policies are examined.

Default rules can also be specified as a catch-all via a __default__ member. Defaults can be provided for either a specific operation (e.g., getters, setters, etc.,) or they can be provided for objects that are not typed. The system works by looking for specific matches, then looking for a default for the operation, and then finally falling back to the global default. The global default is a Deny rule. This forces the capability system to require any supported operation to be explicitly white-listed.

The default policies are useful for enabling support for expando properties (user defined properties on built-in objects) as well as providing generic support for index-referenced objects (e.g., collections and arrays) where it is impossible to define a rule for every value.

Custom Rules

A custom rule can be implemented on any member. Below is a simple example of defining a custom rule for the alert method. In this example, we will rewrite the alert method to set the window defaultStatus property to the displayed argument:

$Policy.JavaScript.__global__.i.alert = 
   function(context)
   {
       // We are augmenting the behavior
       context.invoke = $Rule.Invoke.AUGMENT;
       // set the defaultStatus property on the global object 
       //  to the specified value
       context.sandbox.s(context.src,"defaultStatus",args[0]);
   }

In the above code, to ensure the system is properly secured, we are using the sandbox to set the defaultStatus property on the execution context's root object (the sandboxed equivalent of the window object). If we really wanted this to always to display on the window's status bar, we could elect to set the window.defaultStatus directly. If you choose this latter approach, care must be taken as to ensure the operation cannot be leveraged to leak information. In general, the Sandbox rules always attempt to distill all operations deferring any direct execution to the appropriate rule.