Components.utils.evalInSandbox

  • Revision slug: Components.utils.evalInSandbox
  • Revision title: Components.utils.evalInSandbox
  • Revision id: 101245
  • Created:
  • Creator: Sheppy
  • Is current revision? No
  • Comment 19 words added, 2 words removed

Revision Content

In certain circumstances, you may want to evaluate JavaScript code with restricted privileges. In Firefox 1.5 (Gecko 1.8) or later, an API exists to allow you to do this. It contains the notion of a "sandbox" that you can create and evaluate code in its context. Code evaluated using this method will always execute with restricted privileges, as on a normal web page.

Note: It's not safe to use evalInSandbox() to evaluate JSON strings; instead, use the techniques discussed in the article on JSON. You can also find Firefox 3.5 specific information in Using JSON in Firefox.

Use

To use evalInSandbox(), you must first create a sandbox object using its constructor, Components.utils.Sandbox.

{{ gecko_callout_heading("2.0") }}

The syntax of the Components.utils.Sandbox constructor changed in Gecko 2.0 {{ geckoRelease("2.0") }}. Previously, the optional parameters were passed directly to the constructor instead of being properties of the optional parameters object. See that article for details on this change.

The sandbox is just an empty JavaScript object marked as being created by the restricted privilege principal. It will become the global scope object when you pass it to evalInSandbox(text, sandbox). You may want to add objects to this scope. For example:

var mySandbox = Components.utils.Sandbox("http://www.example.com/");
s.y = 5;  // insert property 'y' with value 5 into global scope.
var result = Components.utils.evalInSandbox("x = y + 2; x + 3", s);
// result is 10, s.x is now 7

Operations on objects you insert into this sandbox global scope do not carry privileges into the sandbox:

s.foo = Components;
// this will give a "Permission Denied" error
Components.utils.evalInSandbox("foo.classes", s);

On the other hand, any function that comes out of the sandbox executes with the privileges of chrome code. This can happen in a surprising number of ways as you can see in the next section.

Security

Security warning: There is potential for security problems to arise when using evalInSandbox() if you rely on the properties of an object resulting from the code executed in the sandbox.

Some examples:

<script src="prototype.js"></script>

<script>
var s = new Components.utils.Sandbox(url);
var x = Components.utils.evalInSandbox(untrusted_code, s);
if (x == 1) {
  /* this code is unsafe; calls x.valueOf() */
}

if (x === 1) {
  /* this code is safe */
}

var y = x.y; /* this is unsafe */
var z = sandbox.z; /* unsafe */

if (typeof x == "number") {
  /* safe */
}
</script>

To understand how the security risk arises, let's take the example of (x == 1). When this is evaluated, the x.valueOf() method gets called by chrome code. When this happens, unsafe code can create a String object in the chrome code's global scope.

If the chrome code has added a function that has chrome privileges to String.prototype, Object.prototype, or Function.prototype, then unsafe code can abuse that function. What the unsafe code can do depends on what that function is, but the unsafe code can wind up being executed with chrome privileges.

To avoid this potential security risk, you should either carefully avoid using objects resulting from evalInSandbox() in any way that might result in a function in that object being called, or you should make sure that untrusted JSON strings don't contain any functions or expressions before using evalInSandbox() to evaluate them.

See also: PiggyBank analysis of sandbox

Optional Arguments

As of Firefox 3.5/Gecko 1.9.1, it's possible to optionally specify the JS version, filename, and line number of the code being evaluated. For instance:

var x = Components.utils.evalInSandbox("let x = 1;", sandbox, "1.8", "http://foo.com/mycode.js", 25);

The above will execute code using JavaScript 1.8.  Any exceptions raised by the evaluated code will show as originating from the above URL.  The evaluated code is assumed to start at line 25 of the document at that URL.

This functionality was added as a result of #445873.

{{ languages( { "ja": "ja/Components.utils.evalInSandbox", "zh-cn": "cn/Components.utils.evalInSandbox" } ) }}

Revision Source

<p>In certain circumstances, you may want to evaluate <a href="/en/JavaScript" title="en/JavaScript">JavaScript</a> code with restricted privileges. In <a href="/en/Firefox_1.5_for_developers" title="en/Firefox_1.5_for_developers">Firefox 1.5</a> (Gecko 1.8) or later, an API exists to allow you to do this. It contains the notion of a "sandbox" that you can create and evaluate code in its context. Code evaluated using this method will always execute with restricted privileges, as on a normal web page.</p>
<div class="note"><strong>Note</strong><strong>:</strong> It's not safe to use <code>evalInSandbox()</code> to evaluate JSON strings; instead, use the techniques discussed in the article on <a class="internal" href="/en/JSON" title="en/JSON">JSON</a>. You can also find Firefox 3.5 specific information in <a class="internal" href="/En/Using_native_JSON" title="en/Using JSON in Firefox">Using JSON in Firefox</a>.</div>
<h2>Use</h2>
<p>To use <code>evalInSandbox()</code>, you must first create a sandbox object using its constructor, <code><a href="/en/Components.utils.Sandbox" title="en/Components.utils.Sandbox">Components.utils.Sandbox</a></code>.</p>
<div class="geckoVersionNote">
<p>{{ gecko_callout_heading("2.0") }}</p>
<p>The syntax of the <code><a href="/en/Components.utils.Sandbox" title="en/Components.utils.Sandbox">Components.utils.Sandbox</a></code> constructor changed in Gecko 2.0 {{ geckoRelease("2.0") }}. Previously, the optional parameters were passed directly to the constructor instead of being properties of the optional parameters object. See that article for details on this change.</p>
</div>
<p>The sandbox is just an empty JavaScript object marked as being created by the restricted privilege principal. It will become the global scope object when you pass it to <code>evalInSandbox(text, sandbox)</code>. You may want to add objects to this scope. For example:</p>
<pre>var mySandbox = Components.utils.Sandbox("<span class="plain">http://www.example.com/</span>");
s.y = 5;  // insert property 'y' with value 5 into global scope.
var result = Components.utils.evalInSandbox("x = y + 2; x + 3", s);
// result is 10, s.x is now 7
</pre>
<p>Operations on objects you insert into this sandbox global scope do not carry privileges into the sandbox:</p>
<pre>s.foo = Components;
// this will give a "Permission Denied" error
Components.utils.evalInSandbox("foo.classes", s);
</pre>
<p>On the other hand, any function that comes out of the sandbox executes with the privileges of chrome code. This can happen in a surprising number of ways as you can see in the next section.</p>
<h2>Security</h2>
<div class="warning"><strong>Security warning:</strong> There is potential for security problems to arise when using <code>evalInSandbox()</code> if you rely on the properties of an object resulting from the code executed in the sandbox.</div>
<p>Some examples:</p>
<pre class="eval">&lt;script src="prototype.js"&gt;&lt;/script&gt;

&lt;script&gt;
var s = new Components.utils.Sandbox(url);
var x = Components.utils.evalInSandbox(untrusted_code, s);
if (x == 1) {
  /* this code is unsafe; calls x.valueOf() */
}

if (x === 1) {
  /* this code is safe */
}

var y = x.y; /* this is unsafe */
var z = sandbox.z; /* unsafe */

if (typeof x == "number") {
  /* safe */
}
&lt;/script&gt;
</pre>
<p>To understand how the security risk arises, let's take the example of <code>(x == 1)</code>. When this is evaluated, the <code>x.valueOf()</code> method gets called by chrome code. When this happens, unsafe code can create a String object in the chrome code's global scope.</p>
<p>If the chrome code has added a function that has chrome privileges to <code>String.prototype</code>, <code>Object.prototype</code>, or <code>Function.prototype</code>, then unsafe code can abuse that function. What the unsafe code can do depends on what that function is, but the unsafe code can wind up being executed with chrome privileges.</p>
<p>To avoid this potential security risk, you should either carefully avoid using objects resulting from <code>evalInSandbox()</code> in any way that might result in a function in that object being called, or you should make sure that untrusted JSON strings don't contain any functions or expressions before using <code>evalInSandbox()</code> to evaluate them.</p>
<p>See also: <a class="external" href="http://simile.mit.edu/wiki/Piggy_Bank_Scraper_Risk">PiggyBank analysis of sandbox</a></p>
<h2>Optional Arguments</h2>
<p>As of Firefox 3.5/Gecko 1.9.1, it's possible to optionally specify the JS version, filename, and line number of the code being evaluated. For instance:</p>
<pre class="eval">var x = Components.utils.evalInSandbox("let x = 1;", sandbox, "1.8", "<a class=" external" href="http://foo.com/mycode.js" rel="freelink">http://foo.com/mycode.js</a>", 25);
</pre>
<p>The above will execute code using JavaScript 1.8.  Any exceptions raised by the evaluated code will show as originating from the above URL.  The evaluated code is assumed to start at line 25 of the document at that URL.</p>
<p>This functionality was added as a result of <a class="link-https" href="https://bugzilla.mozilla.org/show_bug.cgi?id=445873" title="https://bugzilla.mozilla.org/show_bug.cgi?id=445873">#445873</a>.</p>
<p>{{ languages( { "ja": "ja/Components.utils.evalInSandbox", "zh-cn": "cn/Components.utils.evalInSandbox" } ) }}</p>
Revert to this revision