mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 02:09:05 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			318 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			318 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
Script 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
 | 
						|
<https://developer.mozilla.org/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 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.
 | 
						|
   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 <#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 <#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:: images/compartments.png
 | 
						|
 | 
						|
Normal content windows are globals, of course, but so are chrome
 | 
						|
windows, sandboxes, workers, the ``ContentFrameMessageManager`` in a frame
 | 
						|
script, 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:: images/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:: images/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:: images/cross-origin-wrapper.png
 | 
						|
 | 
						|
This denies access to all the object's properties, except for a few
 | 
						|
properties of Window and Location objects, as defined by
 | 
						|
the `same-origin
 | 
						|
policy <https://developer.mozilla.org/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 in
 | 
						|
sandboxes, which are initialized with an `expanded
 | 
						|
principal <#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:: images/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 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 if it wants unfiltered access to the untrusted object.
 | 
						|
 | 
						|
See `Xray vision <xray_vision.html>`__ 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:: images/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()`` and
 | 
						|
``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
 | 
						|
~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
There are four types of security principal: the system principal,
 | 
						|
content principals, expanded principals, and the null principal.
 | 
						|
 | 
						|
.. _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.
 | 
						|
 | 
						|
.. _Content_principal:
 | 
						|
 | 
						|
Content principal
 | 
						|
^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
A content principal is associated with some web content and is defined
 | 
						|
by the 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:: JavaScript
 | 
						|
 | 
						|
   ["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 to give content scripts cross-domain privileges for a predefined set of
 | 
						|
domains,
 | 
						|
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:: images/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:: images/computing-a-wrapper.png
 |