FirefoxOS/New security model/Packaging: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
 
(19 intermediate revisions by 2 users not shown)
Line 44: Line 44:
A packaged is denoted by setting a single packages header which is the signature over the first resource which MUST be the manifest, and must include a list of resources in the package, along with their hashes.
A packaged is denoted by setting a single packages header which is the signature over the first resource which MUST be the manifest, and must include a list of resources in the package, along with their hashes.


   '''manifest-signature: MRjdkly.... (Base64 JWS Signature over manifest content)'''
   '''manifest-signature: MRjdkly.... (Base64 Signature over manifest content)'''


Package headers are specified by the w3c format and are headers which are sent inside the package, but prior to the first data part. Modifiying the above example, we get something like:
Package headers are specified by the w3c format and are headers which are sent inside the package, but prior to the first data part. Modifiying the above example, we get something like:


  '''manifest-signature: MRjdkly.... (Base64 JWS Signature)'''
  '''manifest-signature: MRjdkly.... (Base64 Signature)'''
  --gc0pJq0M:08jU534c0p
  --gc0pJq0M:08jU534c0p
  Content-Location: /someapp.webmanifest
  Content-Location: /someapp.webmanifest
Line 58: Line 58:
  ...
  ...


== App Manifest Extensions ==
== Manifest Requirements ==
==='' package-identifier'' ===
Signed packages must contain a package-identifier field. The unique identifier for a signed package which is used to denote it unique for a given web origin (ie example.com!app1). NOTE: Marketplace will supply this for production packages.


==='' name'' ===
=== ''permissions''===
Signed packages must contain a name field. The unique identifier for a signed package is the tuple of the package origin and the app name. (e.g. foo.com!myapp)
We need the permissions of the signed package so in order to know what permissions to grant to the new process.


=== ''Resources''===
=== ''moz-resources''===
We add a ''resources'' section to the app manifest which enumerates content which needs to have integrity check.  
We add a ''resources'' section to the app manifest which enumerates content which needs to have integrity check. All resources are specified by relative URIs and meaning they must reside inside the package.


=== ''moz-package-origin''===
We need a field in the manifest which specifies the origin for where the package is allowed to be hosted. This needs to be checked by gecko when a package is loaded to ensure that the package hasn't been moved and re-hosted.
=== Example ===
  {
  {
"name": "My App",
"scope": "/",
"start_url": "/index.html",
  "permissions": [
  "permissions": [
   {
   {
Line 80: Line 83:
   }
   }
  ],
  ],
  "resources": [
  "moz-resources": [
   {
   {
     "src": "/index.html",
     "src": "/index.html",
Line 97: Line 100:
       "integrity": "sha256-geijfi...ae3W"
       "integrity": "sha256-geijfi...ae3W"
   }
   }
  ]
  ],
"moz-package-origin":"https://example.com",
"package-identifier":"6213ccd8-7d17-11e5-a6cd-fb1f39b76b9c"
  }
  }
*Question: Do ALL resources need to live INSIDE the package? If we support arbitrary loads this would allow support for non-packaged privileged apps too, but I don't know what complexity this would add to the loading/verification process.
=== ''package-origin''===
We need a field in the manifest which specifies the origin for where the package is allowed to be hosted. This needs to be checked by gecko when a package is loaded to ensure that the package hasn't been moved and re-hosted.
== Processing Model ==
When an app-manifest is encountered, while the page is loaded as normal, additional steps are initiated in parallel. Two main processes are started:
- populating cache with app enumerated resources
- verification of signed resources and granting of permissions
The normal loading process is:
#Gecko loads the manifest
#Gecko checks the signature of the manifest
#If signature verifies, a privileged child process is launched
#Web page is loaded as a normal web page inside this privileged process
#Although the _process_ is privileged, permission are restricted until verification is complete (i.e. ALL resources enumerated in the manifest have been loaded and passed integrity checks)
The verification process is as follows:
# After the manifest signature checks out, gecko starts downloading all files enumerated in the manifest
# Each resource has is checked against a digest from the manifest
# If the integrity check passes, the resource is cached
# Once all the resources have been cached, only then is content considered privileged and permissions available to it
#TODO: How do we enable permissions in a lazy manner? (ie after the window is already loaded)
To update a privileged app:
2.2. Update
# GET manifest, If-Modified-Since
# Look for what files have changed, by addition/deletion/integrity
# Update changed files
Verification failures are generally treated as network failures. See "Error Recovery" below for the approach to dealing with loading errors and partially loaded apps.
== Cache population ==
TODO (initial thoughts only)
* For all signed resources we should only cache them if the integrity check passes
* We want to somehow keep track of the resources that have been integrity checked (if we adhere to the previous rule, can we assume that if cached, then the resource passed the integrity check?
== Verification of resources & Permission Granting==
TODO
* We only want to grant permissions after ALL resources in the manifest have been verified
* But we want to launch the process earlier to speed up performance
* We'll need some kind of verifier worker that keeps track of loading, and link this to the PermissionManager (and apps manager, at least while we have an apps manager)
* The delay here shouldn't be a problem for most privileged APIs, since MOST permissions are user granted, and therefore asynchronous by their nature. There will be a some complexity though as there are a number of APIs which are st to null if a permission is not present when the window(?) is created. We are going to need to make ALL permissions grant-able at any stage.
== Error Handling & Recovery ==
= Security Properties of Privileged Apps =
* Only signed scripts may be loaded
* Only signed entry points can be navigated to
* All privileged content must be served over a secure network connection. 
* No framing privileged content
* Resources enumerated in the manifest must have their integrity checked prior to loading
Note:
* Not all HTML must be signed. There is little value in making this a firm requirement since it isn't possible to prevent dynamic HTML changes (this risk is unchanged from previous packaged approach)
* The resources which MUST be signed are:
** scripts (CSP enforces that only signed scripts can be loaded in the origin)
** entry points (entry point restrictions enforce that only signed entry points can be navigated to)
* Developers should be encouraged to sign all static resources to prevent tampering

Latest revision as of 12:00, 23 November 2015

Privileged Content

This page details implementation of signed privileged content for FxOS. The basic properties of privileged content is that:

  • they are enumerated in a manifest
  • signed to prevent modification
  • loaded into a unique origin which is granted special permissions(separate from other web content on the same domain)

Background: Packaged Content

bug 1036275 introduced packaged HTML content to Firefox. Packages must be served with "Content-Type: application/package" mime type.

An example of a regular package is shown below:

--gc0pJq0M:08jU534c0p
Content-Location: /index.html
Content-Type: text/html

<html>
  <head>
    <script src="scripts/app.js"></script>
    ...
  </head>
  ...
</html>

--gc0pJq0M:08jU534c0p
Content-Location: /scripts/app.js
Content-Type: text/javascript

module Math from '/scripts/helpers/math.js';
...

--gc0pJq0M:08jU534c0p
Content-Location: /scripts/helpers/math.js
Content-Type: text/javascript

export function sum(nums) { ... }
...

--gc0pJq0M:08jU534c0p--

Privileged Packages

The Signed Manifest

A packaged is denoted by setting a single packages header which is the signature over the first resource which MUST be the manifest, and must include a list of resources in the package, along with their hashes.

  manifest-signature: MRjdkly.... (Base64 Signature over manifest content)

Package headers are specified by the w3c format and are headers which are sent inside the package, but prior to the first data part. Modifiying the above example, we get something like:

manifest-signature: MRjdkly.... (Base64 Signature)
--gc0pJq0M:08jU534c0p
Content-Location: /someapp.webmanifest
Content-Type: application/manifest

{
"name": "My App", 
"description":"A great app!"
...

Manifest Requirements

package-identifier

Signed packages must contain a package-identifier field. The unique identifier for a signed package which is used to denote it unique for a given web origin (ie example.com!app1). NOTE: Marketplace will supply this for production packages.

permissions

We need the permissions of the signed package so in order to know what permissions to grant to the new process.

moz-resources

We add a resources section to the app manifest which enumerates content which needs to have integrity check. All resources are specified by relative URIs and meaning they must reside inside the package.

moz-package-origin

We need a field in the manifest which specifies the origin for where the package is allowed to be hosted. This needs to be checked by gecko when a package is loaded to ensure that the package hasn't been moved and re-hosted.

Example

{
"permissions": [
  {
    "systemXHR": {
      "description": "Needed to download stuff"
    },
    "devicestorage:pictures": {
      "description": "Need to load pictures"
    }
  }
],
"moz-resources": [
  {
    "src": "/index.html",
    "integrity": "sha256-kass...eoirW-e"
  },
  {
    "src": "/page2.html",
    "integrity": "sha256-kasguie...ngeW-e"
  },
  {
    "src": "/script.js",
    "integrity": "sha256-agjdia2...wgda"
  },
  {
    "src": "/library.js",
     "integrity": "sha256-geijfi...ae3W"
  }
],
"moz-package-origin":"https://example.com",
"package-identifier":"6213ccd8-7d17-11e5-a6cd-fb1f39b76b9c"
}