Components.utils.Sandbox
is used to create a sandbox object for use with evalInSandbox()
.
To create a new sandbox, call Components.utils.Sandbox
:
var sandbox = Components.utils.Sandbox(principal[, options]);
Using new Components.utils.Sandbox(...)
to create a sandbox has the same effect as calling Sandbox(...)
without new
.
The created sandbox is simply an empty JavaScript object marked as having been created by the restricted privilege principal. You can then use it with evalInSandbox()
to make it the global scope object for the specified script.
The security principal defined for a sandbox determines what code running in that sandbox will be allowed to do. The principal may be one of four types: the system principal, a content principal, an expanded principal, or a null principal.
See Security checks for more information on security principals.
To specify the system principal, you can create it using code like:
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);
You can specify a content principal for a particular origin in one of three ways:
nsIPrincipal
, for example by using the nodePrincipal
property of a DOM nodensIDOMWindow
, such as that returned by the DOM window
propertyWhen possible, specify a window or an nsIPrincipal
object instead of using a string URI. Window objects and nsIPrincipal
carry additional information such as origin attributes and same-origin privilege changes caused by setting document.domain
.
Example of obtaining content principal from the window:
var principal = gBrowser.selectedTab.linkedBrowser.contentPrincipal; var sandbox = Components.utils.Sandbox(principal);
An expanded principal is specified as an array of the principals it subsumes. Each item in the array should be an nsIPrincipal
, a DOM window, or a URI. So this can be simply an array with a single element. For example the content principal above can be made expanded/extended like so:
var principal = [gBrowser.selectedTab.linkedBrowser.contentPrincipal]; // this is now an expanded (aka extended) principal var sandbox = Components.utils.Sandbox(principal);
You can create a null principal using code like:
Cc["@mozilla.org/nullprincipal;1"].createInstance(Ci.nsIPrincipal);
From Firefox 37 onwards, you can also specify the null principal by simply passing null
as the principal
argument.
The constructor accepts an optional parameter. This parameter is an object with the following optional properties:
freshZone
window
object will want to use sameZoneAs
instead.sameZoneAs
window
they're running in as this parameter, in order to ensure that the script is cleaned up at the same time as the content itself.sandboxName
A string value which identifies the sandbox in about:memory (and possibly other places in the future). This property is optional, but very useful for tracking memory usage of add-ons and other JavaScript compartments. A recommended value for this property is an absolute path to the script responsible for creating the sandbox. As of Gecko 13 (Firefox 13.0 / Thunderbird 13.0 / SeaMonkey 2.10), if you don't specify a sandbox name it will default to the caller's filename.
sandboxPrototype
A prototype object for the sandbox. The sandbox will inherit the contents of this object if it's provided.
Passing a content window
object, setting wantXrays:true
(default) and using an extended principal provides a clean, isolated execution environment in which javascript code that needs Web APIs (such as accessing the window's DOM) can be executed without interference from untrusted content code.
wantComponents
A Boolean indicating whether the Components
object is available or not in the sandbox. Default: true
.
If the sandbox interacts with untrusted content this should be set to false
when possible to further reduce possible attack surface.
wantExportHelpers
A Boolean: if true, then createObjectIn()
, evalInWindow()
, and exportFunction()
are available in the sandbox. Default: false
.
wantGlobalProperties
-Promise
": the Promise
constructor is available by default for sandboxes, and you use this option to remove it from the sandbox. Note that "-Promise"
is removed in Firefox 37.-Promise (removed in Firefox 37) |
CSS |
indexedDB (Web Worker only) |
XMLHttpRequest |
TextEncoder |
TextDecoder |
URL |
URLSearchParams |
atob |
btoa |
Blob |
File |
crypto |
rtcIdentityProvider |
fetch (added in Firefox 41) |
caches |
FileReader |
For example:
var sandboxScript = 'var encoded = btoa("Hello");' + 'var decoded = atob(encoded);'; var options = { "wantGlobalProperties": ["atob", "btoa"] } var sandbox = Components.utils.Sandbox("https://example.org/", options); Components.utils.evalInSandbox(sandboxScript, sandbox); console.log(sandbox.encoded); // "SGVsbG8=" console.log(sandbox.decoded); // "Hello"
wantXHRConstructor
wantGlobalProperties
instead.wantXrays
A Boolean value indicating whether the sandbox wants Xray vision with respect to same-origin objects outside the sandbox. Default: true
.
“Xray vision” is exactly the same Xray behavior that script always gets, by default, when working with DOM objects across origin boundaries. This is primarily visible for chrome code accessing content. However, it also occurs during cross-origin access between two content pages, since each page sees a "vanilla" view of the other. The protection is bidirectional: the caller sees the bonafide DOM objects without being confused by sneakily-redefined properties, and the target receives appropriate privacy from having its expandos inspected by untrusted callers. In situations where only unidirectional protection is needed, callers have the option to waive the X-ray behavior using wrappedJSObject
or XPCNativeWrapper.unwrap().
In general, when accessing same-origin content, script gets a Transparent wrapper rather than an Xray wrapper. However, sandboxes are often used when chrome wants to run script as another origin, possibly to interact with the page. In this case, same-origin Xrays are desirable, and wantXrays
should be set to
true
.
See Safely accessing content DOM from chrome for more details.
dump()
- Similar to window.dump().
debug()
For more information on the built-in Sandbox functions, please consult the source code.
You can import functions or objects into the sandbox simply by assigning them to the sandbox object. For example:
mysandbox.doSomething = function() { ... };
Complex objects can be cloned into the sandbox using Components.utils.cloneInto
:
mysandbox.someObject = Components.utils.cloneInto({ a: 'string', b: 21 }, mysandbox);
Obviously you need to consider the security implications of the functions you import. This technique isn't limited to functions - it can be used to import objects or values.
When you have finished using a sandbox, it should be freed to avoid memory leaks. Generally the JavaScript garbage collector will take care of this when there are no remaining references to the sandbox or the code it contains. However, in some cases it can be difficult to remove all references. For example, the code in the sandbox might be a third-party library that sets expando properties or adds event listeners to a window. In this case, Components.utils.nukeSandbox
can be used to force the sandbox to be freed immediately.
More ways to load scripts into a sandbox can be found on the Loading Scripts page.
This example is to be run from scratchpad with environemnt set to browser. It alerts the dollar sign function. This code was tested on twitter.com and gets access to the jQuery $.
var sandboxScript = 'alert($)'; var options = { sandboxPrototype: content, wantXrays: false // only set this to false if you need direct access to the page's javascript. true provides a safer, isolated context. }; var sandbox = Cu.Sandbox(content, options); Cu.evalInSandbox(sandboxScript, sandbox); Cu.nukeSandbox(sandbox);