Bobby Holley 2021-07-29 15:22:44 +00:00
Родитель 5064274394
Коммит 0f3e29f15d
10 изменённых файлов: 771 добавлений и 0 удалений

Двоичные данные
dom/docs/scriptSecurity/images/compartments.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 203 KiB

Двоичные данные
dom/docs/scriptSecurity/images/computing-a-wrapper.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 276 KiB

Двоичные данные
dom/docs/scriptSecurity/images/cross-compartment-wrapper.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 52 KiB

Двоичные данные
dom/docs/scriptSecurity/images/cross-origin-wrapper.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 55 KiB

Двоичные данные
dom/docs/scriptSecurity/images/opaque-wrapper.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 54 KiB

Двоичные данные
dom/docs/scriptSecurity/images/principal-relationships.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 144 KiB

Двоичные данные
dom/docs/scriptSecurity/images/same-origin-wrapper.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 55 KiB

Двоичные данные
dom/docs/scriptSecurity/images/xray-wrapper.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 54 KiB

Просмотреть файл

@ -0,0 +1,340 @@
--- title: Script security slug: Mozilla/Gecko/Script_security tags: -
Security ---
.. container:: summary
This page provides an overview of the script security architecture in
Gecko.
Like any web browser, Gecko can load JavaScript from untrusted and
potentially hostile web pages and run it on the user's computer. The
security model for web content is based on the `same-origin
policy </en-US/docs/Web/Security/Same-origin_policy>`__, in which code
gets full access to objects from its origin but highly restricted access
to objects from a different origin. The rules for determining whether an
object is same-origin with another, and what access is allowed
cross-origin, are now mostly standardized across browsers.
Gecko has an additional problem, though: while its core is written in
C++, the front-end code is written in JavaScript. This JavaScript code,
which is commonly referred to as c\ *hrome code*, runs with system
privileges. If the code is compromised, the attacker can take over the
user's computer. Legacy `SDK extensions </en-US/Add-ons/SDK>`__ also run
with chrome privileges.
Having the browser front end in JavaScript has benefits: it can be much
quicker to develop in JavaScript than in C++, and contributors do not
need to learn C++. However, JavaScript is a highly dynamic, malleable
language, and without help it's difficult to write system-privileged
code that interacts safely with untrusted web content. From the point of
view of chrome code, the script security model in Gecko is intended to
provide that help to make writing secure, system-privileged JavaScript a
realistic expectation.
.. _Security_policy:
Security policy
---------------
Gecko implements the following security policy:
- **Objects that are same-origin** are able to access each other
freely. For example, the objects associated with a document served
from *https://example.org/* can access each other, and they can also
access objects served from *https://example.org/foo*.
- **Objects that are cross-origin** get highly restricted access to
each other, according to the `same-origin
policy </en-US/docs/Web/Security/Same-origin_policy#Cross-origin_script_API_access>`__.
For example, code served from *https://example.org/* trying to access
objects from *https://somewhere-else.org/* will have restricted
access.
- **Objects in a privileged scope** are allowed complete access to
objects in a less privileged scope, but by default they see a
`restricted
view </en-US/docs/Mozilla/Gecko/Script_security#Privileged_to_unprivileged_code>`__
of such objects, designed to prevent them from being tricked by the
untrusted code. An example of this scope is chrome-privileged
JavaScript accessing web content.
- **Objects in a less privileged scope** don't get any access to
objects in a more privileged scope, unless the more privileged scope
`explicitly clones those
objects </en-US/docs/Mozilla/Gecko/Script_security#Unprivileged_to_privileged_code>`__.
An example of this scope is web content accessing objects in a
chrome-privileged scope. 
.. _Compartments:
Compartments
------------
Compartments are the foundation for Gecko's script security
architecture. A compartment is a specific, separate area of memory. In
Gecko, there's a separate compartment for every global object. This
means that each global object and the objects associated with it live in
their own region of memory.
.. image:: https://mdn.mozillademos.org/files/9697/compartments.png
Normal content windows are globals, of course, but so are chrome
windows, `sandboxes </en-US/docs/Components.utils.Sandbox>`__,
`workers </en-US/docs/Web/API/Worker>`__, the
``ContentFrameMessageManager`` in a `frame
script </en-US/Firefox/Multiprocess_Firefox/Frame_script_environment>`__,
and so on.
Gecko guarantees that JavaScript code running in a given compartment is
only allowed to access objects in the same compartment. When code from
compartment A tries to access an object in compartment B, Gecko gives it
a *cross-compartment wrapper*. This is a proxy in compartment A for the
real object, which lives in compartment B.
.. image:: https://mdn.mozillademos.org/files/9729/cross-compartment-wrapper.png
Inside the same compartment, all objects share a global and are
therefore same-origin with each other. Therefore there's no need for any
security checks, there are no wrappers, and there is no performance
overhead for the common case of objects in a single window interacting
with each other.
Whenever cross-compartment access happens, the wrappers enable us to
implement the appropriate security policy. Because the wrapper we choose
is specific to the relationship between the two compartments, the
security policy it implements can be static: when the caller uses the
wrapper, there's no need to check who is making the call or where it is
going.
.. _Cross-compartment_access:
Cross-compartment access
------------------------
.. _Same-origin:
Same-origin
~~~~~~~~~~~
As we've already seen, the most common scenario for same-origin access
is when objects belonging to the same window object interact. This all
takes place within the same compartment, with no need for security
checks or wrappers.
When objects share an origin but not a global - for example two web
pages from the same protocol, port, and domain - they belong to two
different compartments, and the caller gets a *transparent wrapper* to
the target object.
.. image:: https://mdn.mozillademos.org/files/9735/same-origin-wrapper.png
Transparent wrappers allow access to all the target's properties:
functionally, it's as if the target is in the caller's compartment.
.. _Cross-origin:
Cross-origin
~~~~~~~~~~~~
If the two compartments are cross-origin, the caller gets a
*cross-origin wrapper*.
.. image:: https://mdn.mozillademos.org/files/9731/cross-origin-wrapper.png
This denies access to all the object's properties, except for a few
properties of ```Window`` </en-US/docs/Web/API/Window>`__ and
```Location`` </en-US/docs/Web/API/Location>`__ objects, as defined by
the `same-origin
policy </en-US/docs/Web/Security/Same-origin_policy#Cross-origin_script_API_access>`__.
.. _Privileged_to_unprivileged_code:
Privileged to unprivileged code
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The most obvious example of this kind of security relation is between
system-privileged chrome code and untrusted web content, but there are
other examples in Gecko. The Add-on SDK runs `content
scripts </en-US/Add-ons/SDK/Guides/Content_Scripts>`__ in
`sandboxes </en-US/docs/Components.utils.Sandbox>`__, which are
initialized with an `expanded
principal </en-US/docs/Mozilla/Gecko/Script_security#Expanded_principal>`__,
giving them elevated privileges with respect to the web content they
operate on, but reduced privileges with respect to chrome.
If the caller has a higher privilege than the target object, the caller
gets an *Xray wrapper* for the object.
.. image:: https://mdn.mozillademos.org/files/9737/xray-wrapper.png
Xrays are designed to prevent untrusted code from confusing trusted code
by redefining objects in unexpected ways. For example, privileged code
using an Xray to a DOM object sees only the original version of the DOM
object. Any
`expando <https://developer.mozilla.org/en-US/docs/Glossary/Expando>`__
properties are not visible, and if any native DOM properties have been
redefined, they are not visible in the Xray.
The privileged code is able to `waive
Xrays </en-US/docs/Components.utils.waiveXrays>`__ if it wants
unfiltered access to the untrusted object.
See `Xray vision </en-US/docs/Xray_vision>`__ for much more information
on Xrays.
.. _Unprivileged_to_privileged_code:
Unprivileged to privileged code
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If the caller has lower privileges than the target object, then the
caller gets an *opaque wrapper.*
.. image:: https://mdn.mozillademos.org/files/9733/opaque-wrapper.png
An opaque wrapper denies all access to the target object.
However, the privileged target is able to copy objects and functions
into the less privileged scope using the
```exportFunction()`` </en-US/docs/Components.utils.exportFunction>`__
and ```cloneInto()`` </en-US/docs/Components.utils.cloneInto>`__
functions, and the less privileged scope is then able to use them.
.. _Security_checks:
Security checks
---------------
To determine the security relation between two compartments, Gecko uses
two concepts: *security principals* and the act of *subsuming*. To
establish the security relationship between two compartments A and B,
Gecko asks:
*Does the security principal for compartment A subsume the security
principal for compartment B, and vice versa?*
.. _Subsumes:
Subsumes
~~~~~~~~
+-----------------------------------+-----------------------------------+
| *A subsumes B* | A has all of the privileges of B, |
| | and possibly more, and therefore |
| | A is allowed to see and do |
| | anything that B can see and do. |
+-----------------------------------+-----------------------------------+
| *A Subsumes B &&* *B Subsumes A* | A and B are same-origin. |
+-----------------------------------+-----------------------------------+
| *A Subsumes B && B !Subsumes A* | A is more privileged than B. |
| | |
| | A gets access to all of B, by |
| | default with Xray vision, which |
| | it may choose to waive. |
| | |
| | B gets no access to A, although A |
| | may choose to export objects to |
| | B. |
+-----------------------------------+-----------------------------------+
| *A !Subsumes B && B !Subsumes A* | A and B are cross-origin. |
+-----------------------------------+-----------------------------------+
.. _Security_principals:
Security principals
~~~~~~~~~~~~~~~~~~~
.. container::
There are four types of security principal: the system principal,
content principals, expanded principals, and the null principal.
.. container::
.. _System_principal:
System principal
^^^^^^^^^^^^^^^^
The system principal passes all security checks. It subsumes itself and
all other principals. Chrome code, by definition, runs with the system
principal, as do `frame
scripts </en-US/Firefox/Multiprocess_Firefox/Frame_script_environment>`__.
.. _Content_principal:
Content principal
^^^^^^^^^^^^^^^^^
A content principal is associated with some web content and is defined
by the
`origin </en-US/docs/Web/Security/Same-origin_policy#Definition_of_an_origin>`__
of the content. For example, a normal DOM window has a content principal
defined by the window's origin. A content principal subsumes only other
content principals with the same origin. It is subsumed by the system
principal, any expanded principals that include its origin, and any
other content principals with the same origin.
.. _Expanded_principal:
Expanded principal
^^^^^^^^^^^^^^^^^^
An expanded principal is specified as an array of origins:
.. code:: brush:
["http://mozilla.org", "http://moz.org"]
The expanded principal subsumes every content principal it contains. The
content principals do not subsume the expanded principal, even if the
expanded principal only contains a single content principal.
Thus ``["http://moz.org"]`` subsumes ``"http://moz.org"`` but not vice
versa. The expanded principal gets full access to the content principals
it contains, with Xray vision by default, and the content principals get
no access to the expanded principal.
This also enables the script security model to treat compartments that
have expanded principals more like part of the browser than like web
content. This means, for example, that it can run when JavaScript is
disabled for web content.
Expanded principals are useful when you want to give code extra
privileges, including cross-origin access, but don't want to give the
code full system privileges. For example, expanded principals are used
in the `Add-on SDK <https://developer.mozilla.org/en-US/Add-ons/SDK>`__
to give content scripts `cross-domain privileges for a predefined set of
domains <https://developer.mozilla.org/en-US/Add-ons/SDK/Guides/Content_Scripts/Cross_Domain_Content_Scripts>`__,
and to protect content scripts from access by untrusted web content,
without having to give content scripts system privileges.
.. _Null_principal:
Null principal
^^^^^^^^^^^^^^
The null principal fails almost all security checks. It has no
privileges and can't be accessed by anything but itself and chrome. It
subsumes no other principals, even other null principals. (This is what
is used when HTML5 and other specs say "origin is a globally unique
identifier".)
.. _Principal_relationships:
Principal relationships
~~~~~~~~~~~~~~~~~~~~~~~
The diagram below summarizes the relationships between the different
principals. The arrow connecting principals A and B means "A subsumes
B".  (A is the start of the arrow, and B is the end.)
.. image:: https://mdn.mozillademos.org/files/9799/principal-relationships.png
.. _Computing_a_wrapper:
Computing a wrapper
-------------------
The following diagram shows the factors that determine the kind of
wrapper that compartment A would get when trying to access an object in
compartment B.
.. image:: https://mdn.mozillademos.org/files/9801/computing-a-wrapper.png

Просмотреть файл

@ -0,0 +1,431 @@
--- title: Xray vision slug: Mozilla/Tech/Xray_vision tags: - Gecko -
X-Ray Vision - XPCOM ---
.. container:: summary
Xray vision helps JavaScript running in a privileged security context
safely access objects created by less privileged code, by showing the
caller only the native version of the objects.
Gecko runs JavaScript from a variety of different sources and at a
variety of different privilege levels.
- The JavaScript code that along with the C++ core, implements the
browser itself is called *chrome code* and runs using system
privileges. If chrome-privileged code is compromised, the attacker
can take over the user's computer.
- JavaScript loaded from normal web pages is called *content code*.
Because this code is being loaded from arbitrary web pages, it is
regarded as untrusted and potentially hostile, both to other websites
and to the user.
- As well as these two levels of privilege, chrome code can create
`sandboxes </en-US/docs/Components.utils.Sandbox>`__. The `security
principal </en-US/docs/Components.utils.Sandbox#Sandbox_principal>`__
defined for the sandbox determines its privilege level. If an
Expanded Principal is used, the sandbox is granted certain privileges
over content code and is protected from direct access by content
code.
| The security machinery in Gecko ensures that there's asymmetric access
between code at different privilege levels: so for example, content
code can't access objects created by chrome code, but chrome code can
access objects created by content.
| However, even the ability to access content objects can be a security
risk for chrome code. JavaScript's a highly malleable language.
Scripts running in web pages can add extra properties to DOM objects
(also known as `expando properties </en-US/docs/Glossary/Expando>`__)
and even redefine standard DOM objects to do something unexpected. If
chrome code relies on such modified objects, it can be tricked into
doing things it shouldn't.
| For example:
```window.confirm()`` </en-US/docs/Web/API/Window.confirm>`__ is a DOM
API that's supposed to ask the user to confirm an action, and return a
boolean depending on whether they clicked "OK" or "Cancel". A web page
could redefine it to return ``true``:
.. code:: brush:
window.confirm = function() {
return true;
}
Any privileged code calling this function and expecting its result to
represent user confirmation would be deceived. This would be very naive,
of course, but there are more subtle ways in which accessing content
objects from chrome can cause security problems.
| This is the problem that Xray vision is designed to solve. When a
script accesses an object using Xray vision it sees only the native
version of the object. Any expandos are invisible, and if any
properties of the object have been redefined, it sees the original
implementation, not the redefined version.
| So in the example above, chrome code calling the content's
``window.confirm()`` would get the original version of ``confirm()``,
not the redefined version.
.. note::
It's worth emphasizing that even if content tricks chrome into
running some unexpected code, that code does not run with chrome
privileges. So this is not a straightforward privilege escalation
attack, although it might lead to one if the chrome code is
sufficiently confused.
.. _How_you_get_Xray_vision:
How you get Xray vision
-----------------------
Privileged code automatically gets Xray vision whenever it accesses
objects belonging to less-privileged code. So when chrome code accesses
content objects, it sees them with Xray vision:
.. code:: brush:
// chrome code
var transfer = gBrowser.contentWindow.confirm("Transfer all my money?");
// calls the native implementation
.. note::
Note that using window.confirm() would be a terrible way to implement
a security policy, and is only shown here to illustrate how Xray
vision works.
.. _Waiving_Xray_vision:
Waiving Xray vision
-------------------
| Xray vision is a kind of security heuristic, designed to make most
common operations on untrusted objects simple and safe. However, there
are some operations for which they are too restrictive: for example,
if you need to see expandos on DOM objects. In cases like this you can
waive Xray protection, but then you can no longer rely on any
properties or functions being, or doing, what you expect. Any of them,
even setters and getters, could have been redefined by untrusted code.
| To waive Xray vision for an object you can use
```Components.utils.waiveXrays(object)`` </en-US/docs/Components.utils.waiveXrays>`__,
or use the object's ``wrappedJSObject`` property:
.. code:: brush:
// chrome code
var waivedWindow = Components.utils.waiveXrays(gBrowser.contentWindow);
var transfer = waivedWindow.confirm("Transfer all my money?");
// calls the redefined implementation
.. code:: brush:
// chrome code
var waivedWindow = gBrowser.contentWindow.wrappedJSObject;
var transfer = waivedWindow.confirm("Transfer all my money?");
// calls the redefined implementation
Waivers are transitive: so if you waive Xray vision for an object, then
you automatically waive it for all the object's properties. For example,
``window.wrappedJSObject.document`` gets you the waived version of
``document``.
To undo the waiver again, call
```Components.utils.unwaiveXrays(waivedObject)`` </en-US/docs/Components.utils.unwaiveXrays>`__:
.. code:: brush:
var unwaived = Components.utils.unwaiveXrays(waivedWindow);
unwaived.confirm("Transfer all my money?");
// calls the native implementation
.. _Xrays_for_DOM_objects:
Xrays for DOM objects
---------------------
The primary use of Xray vision is for `DOM
objects </en-US/docs/Web/API/Document_Object_Model>`__: that is, the
objects that represent parts of the web page.
In Gecko, DOM objects have a dual representation: the canonical
representation is in C++, and this is reflected into JavaScript for the
benefit of JavaScript code. Any modifications to these objects, such as
adding expandos or redefining standard properties, stays in the
JavaScript reflection and does not affect the C++ representation.
The dual representation enables an elegant implementation of Xrays: the
Xray just directly accesses the C++ representation of the original
object, and doesn't go to the content's JavaScript reflection at all.
Instead of filtering out modifications made by content, the Xray
short-circuits the content completely.
This also makes the semantics of Xrays for DOM objects clear: they are
the same as the DOM specification, since that is defined using the
`WebIDL <http://www.w3.org/TR/WebIDL/>`__, and the WebIDL also defines
the C++ representation.
.. _Xrays_for_JavaScript_objects:
Xrays for JavaScript objects
----------------------------
Until recently, `built-in JavaScript objects that are not part of the
DOM </en-US/docs/Web/JavaScript/Reference/Global_Objects>`__, such as
``Date``, ``Error``, and ``Object``, did not get Xray vision when
accessed by more-privileged code.
Most of the time this is not a problem: the main concern Xrays solve is
with untrusted web content manipulating objects, and web content is
usually working with DOM objects. For example, if content code creates a
new ``Date`` object, it will usually be created as a property of a DOM
object, and then it will be filtered out by the DOM Xray:
.. code:: brush:
// content code
// redefine Date.getFullYear()
Date.prototype.getFullYear = function() {return 1000};
var date = new Date();
.. code:: brush:
// chrome code
// contentWindow is an Xray, and date is an expando on contentWindow
// so date is filtered out
gBrowser.contentWindow.date.getFullYear()
// -> TypeError: gBrowser.contentWindow.date is undefined
The chrome code will only even see ``date`` if it waives Xrays, and
then, because waiving is transitive, it should expect to be vulnerable
to redefinition:
.. code:: brush:
// chrome code
Components.utils.waiveXrays(gBrowser.contentWindow).date.getFullYear();
// -> 1000
However, there are some situations in which privileged code will access
JavaScript objects that are not themselves DOM objects and are not
properties of DOM objects. For example:
- the ``detail`` property of a
```CustomEvent`` </en-US/docs/Web/API/CustomEvent>`__ fired by
content could be a JavaScript
```Object`` </en-US/docs/Web/JavaScript/Reference/Global_Objects/Object>`__
or
```Date`` </en-US/docs/Web/JavaScript/Reference/Global_Objects/Date>`__
as well as a string or a primitive
- the return value of
```evalInSandbox()`` </en-US/docs/Components.utils.evalInSandbox>`__
and any properties attached to the
```Sandbox`` </en-US/docs/Components.utils.Sandbox>`__ object may be
pure JavaScript objects
Also, the WebIDL specifications are starting to use JavaScript types
such as ``Date`` and ``Promise``: since WebIDL definition is the basis
of DOM Xrays, not having Xrays for these JavaScript types starts to seem
arbitrary.
So, in Gecko 31 and 32 we've added Xray support for most JavaScript
built-in objects.
Like DOM objects, most JavaScript built-in objects have an underlying
C++ state that is separate from their JavaScript representation, so the
Xray implementation can go straight to the C++ state and guarantee that
the object will behave as its specification defines:
.. code:: brush:
// chrome code
var sandboxScript = 'Date.prototype.getFullYear = function() {return 1000};' +
'var date = new Date(); ';
var sandbox = Components.utils.Sandbox("https://example.org/");
Components.utils.evalInSandbox(sandboxScript, sandbox);
// Date objects are Xrayed
console.log(sandbox.date.getFullYear());
// -> 2014
// But you can waive Xray vision
console.log(Components.utils.waiveXrays(sandbox.date).getFullYear());
// -> 1000
.. note::
To test out examples like this, you can use the `Scratchpad in
browser
context </en-US/docs/Tools/Scratchpad#Running_Scratchpad_in_the_browser_context>`__
for the code snippet, and the `Browser
Console </en-US/docs/Tools/Browser_Console>`__ to see the expected
output.
Because code running in Scratchpad's browser context has chrome
privileges, any time you use it to run code, you need to understand
exactly what the code is doing. That includes the code samples in
this article.
.. _Xray_semantics_for_Object_and_Array:
Xray semantics for Object and Array
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The exceptions are
```Object`` </en-US/docs/Web/JavaScript/Reference/Global_Objects/Object>`__
and ``Array``: their interesting state is in JavaScript, not C++. This
means that the semantics of their Xrays have to be independently
defined: they can't simply be defined as "the C++ representation".
The aim of Xray vision is to make most common operations simple and
safe, avoiding the need to access the underlying object except in more
involved cases. So the semantics defined for ``Object`` and ``Array``
Xrays aim to make it easy for privileged code to treat untrusted objects
like simple dictionaries.
Any `value
properties </en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty>`__
of the object are visible in the Xray. If the object has properties
which are themselves objects, and these objects are same-origin with the
content, then their value properties are visible as well.
There are two main sorts of restrictions:
- First, the chrome code might expect to rely on the prototype's
integrity, so the object's prototype is protected:
- the Xray has the standard ``Object`` or ``Array`` prototype,
without any modifications that content may have done to that
prototype. The Xray always inherits from this standard prototype,
even if the underlying instance has a different prototype.
- if a script has created a property on an object instance that
shadows a property on the prototype, the shadowing property is not
visible in the Xray
- Second, we want to prevent the chrome code from running content code,
so functions and `accessor
properties </en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty>`__
of the object are not visible in the Xray.
These rules are demonstrated in the script below, which evaluates a
script in a sandbox, then examines the object attached to the sandbox.
.. note::
To test out examples like this, you can use the `Scratchpad in
browser
context </en-US/docs/Tools/Scratchpad#Running_Scratchpad_in_the_browser_context>`__
for the code snippet, and the `Browser
Console </en-US/docs/Tools/Browser_Console>`__ to see the expected
output.
Because code running in Scratchpad's browser context has chrome
privileges, any time you use it to run code, you need to understand
exactly what the code is doing. That includes the code samples in
this article.
.. code:: brush:
/*
The sandbox script:
* redefines Object.prototype.toSource()
* creates a Person() constructor that:
* defines a value property "firstName" using assignment
* defines a value property which shadows "constructor"
* defines a value property "address" which is a simple object
* defines a function fullName()
* using defineProperty, defines a value property on Person "lastName"
* using defineProperty, defines an accessor property on Person "middleName",
which has some unexpected accessor behavior
*/
var sandboxScript = 'Object.prototype.toSource = function() {'+
' return "not what you expected?";' +
'};' +
'function Person() {' +
' this.constructor = "not a constructor";' +
' this.firstName = "Joe";' +
' this.address = {"street" : "Main Street"};' +
' this.fullName = function() {' +
' return this.firstName + " " + this.lastName;'+
' };' +
'};' +
'var me = new Person();' +
'Object.defineProperty(me, "lastName", {' +
' enumerable: true,' +
' configurable: true,' +
' writable: true,' +
' value: "Smith"' +
'});' +
'Object.defineProperty(me, "middleName", {' +
' enumerable: true,' +
' configurable: true,' +
' get: function() { return "wait, is this really a getter?"; }' +
'});';
var sandbox = Components.utils.Sandbox("https://example.org/");
Components.utils.evalInSandbox(sandboxScript, sandbox);
// 1) trying to access properties in the prototype that have been redefined
// (non-own properties) will show the original 'native' version
// note that functions are not included in the output
console.log("1) Property redefined in the prototype:");
console.log(sandbox.me.toSource());
// -> "({firstName:"Joe", address:{street:"Main Street"}, lastName:"Smith"})"
// 2) trying to access properties on the object that shadow properties
// on the prototype will show the original 'native' version
console.log("2) Property that shadows the prototype:");
console.log(sandbox.me.constructor);
// -> function()
// 3) value properties defined by assignment to this are visible:
console.log("3) Value property defined by assignment to this:");
console.log(sandbox.me.firstName);
// -> "Joe"
// 4) value properties defined using defineProperty are visible:
console.log("4) Value property defined by defineProperty");
console.log(sandbox.me.lastName);
// -> "Smith"
// 5) accessor properties are not visible
console.log("5) Accessor property");
console.log(sandbox.me.middleName);
// -> undefined
// 6) accessing a value property of a value-property object is fine
console.log("6) Value property of a value-property object");
console.log(sandbox.me.address.street);
// -> "Main Street"
// 7) functions defined on the sandbox-defined object are not visible in the Xray
console.log("7) Call a function defined on the object");
try {
console.log(sandbox.me.fullName());
}
catch (e) {
console.error(e);
}
// -> TypeError: sandbox.me.fullName is not a function
// now with waived Xrays
console.log("Now with waived Xrays");
console.log("1) Property redefined in the prototype:");
console.log(Components.utils.waiveXrays(sandbox.me).toSource());
// -> "not what you expected?"
console.log("2) Property that shadows the prototype:");
console.log(Components.utils.waiveXrays(sandbox.me).constructor);
// -> "not a constructor"
console.log("3) Accessor property");
console.log(Components.utils.waiveXrays(sandbox.me).middleName);
// -> "wait, is this really a getter?"
console.log("4) Call a function defined on the object");
console.log(Components.utils.waiveXrays(sandbox.me).fullName());
// -> "Joe Smith"