Changes

Jump to: navigation, search

Apps/Security

22,014 bytes added, 04:48, 9 August 2012
no edit summary
The intent of this page is to provide some background for how security works in B2G and Desktop/Android OpenWebApps. The target audience for this page is (at least for now) primarily people working on implementing B2G and the Open Webapps runtimes. Over time we should improve the pieces that affect web developers such that they can be used as developer documentation.
 
=Open Web Apps Security and Privacy Model=
To provide a "trail of activity", B2G or other app runtime could additionally maintain a capability-access log for each app that keeps track of requests for capabilities and the usage intentions over time. That way a curious user could analyze the log to see how often an app used a permission, why it used it, and perhaps help illustrate abuse of their consent.
==Resolved Questions=====Network access===
Network access is assumed as an implicit permission for all apps (as it seems strange to prevent access to something all web content normally has). However the issue of network consumption has been raised as a valid concern.
Its not clear this is an issue for the security model to solve however, and would be better solved via an explicit consumption API that can help the user manage and limit resource utilization. Considered out of scope for the security model in general.
===Background Apps===
Apps running in the background may trigger permission requests. Since app requests should be in context of the user's interaction with the app, we should suppress any permission requests for non-foreground apps. It is up the developer to properly surface permissions requests while the app is interacting with the user.
===Background Services===
Services need to be certified apps as they have no way of surfacing permission requests to users since they have no UI. This means we should minimize the set of use cases that absolutely require true services.
===Power User===Power users should be able to override the default trust roots to allow them to install arbitrary apps as privileged or certified. This is highly dangerous and should include a correspondingly strong disclaimeror equivalent workflow.
===Same Origin Policy===Same origin policy should not be enforced for certified apps or privileged apps, since each app has its own cookie store. The app would have to declare its intent to bypass same-origin policy.
===Cookie & Password management===
Cookies and passwords are stored per app.
===Format for privileged and certified apps===
We need an application delivery mechanism that provides assurances on app integrity and authenticity, and also allows for well-defined application & privilege scope enforcement so integrity can be maintained at runtime.
Privileged and certified apps will be accessed via a unique scheme (app://). The domain will correspond to the source of the app. For example, if an app is from "mozilla.org" the corresponding URI for the app would be "app://mozilla.org".
==Open questions=====Application Scope===
Foundational assumption was that there was only one app per domain. This is because an origin is effectively the only security boundary in the browser, and determining the security implications of allowing apps with different permissions on the same domain is a time consuming exercise for the 1.0 timeframe.
Note that privileged and certified apps have their own unique origin via the app:// scheme.
===Privileged Application Review Guidelines===
We need a set of guidelines that define an acceptable level of security and privacy review for privileged applications. This should include:
*Ensuring that requested permissions are used for the purposes stated (in the permission rationale)
*Use of implicit permissions is appropriate
*Any interfaces between privileged app content and unprivileged external content have appropriate mitigations to prevent elevation of privilege attacks
 
== Application sandboxing ==
 
=== Data stored per app ===
 
Each application runs in as a separate sandbox, meaning that all data stored by an application is separate from all data stored by another application. This includes things like cookie data, localStorage data, indexedDB data and site permissions.
 
This means that if the user has two apps installed, App A and App B, these apps will have completely different set of cookies, different local data and different permission. This even applies if both of these apps open an <iframe> which point to the same origin. I.e. if both App A and App B open an <iframe> pointing to "http://www.mozilla.org", they will both render the website, however the website will be fetched and rendered with different cookies in the two apps.
 
A result of this is that if the user logs in to, for example, facebook while using App A, this in no way affects App Bs ability to interact with the users account on facebook. The login cookie that facebook sets when the user logs in using App A is only available in App A. If App B open an <iframe> to facebook, the cookie wouldn't be there and so when App B opens facebook, it receives the facebook login page rather than the users account.
 
=== Apps can't open each other ===
 
This means that apps can't open other apps by using iframes. If App A creates an iframe with the src set to the URL of App B, this won't actually open App B in the iframe. It will simply open the website located at that URL. It will not use any of App B's cookies and so it will behave no different than as if App B wasn't installed on the user's device.
 
This applies even for packaged apps (more about them below). If App A tries to open the packaged App B by using an <iframe> pointing to the app:// URL of App B, this will simply fail to load. If this results in a 404, or some other type of error is still to be determined, but it will definitely fail to load. And it will fail in the same way no matter if App B is installed on the user's device or not, as to make it impossible for App A to determine if App B is installed.
 
The same thing happens if the top-level frame of App A is navigated to a URL for App B. We always know for a given frame which app is opened in it, and so when attempting to load the App B URL in the App A frame, this will behave exactly like the two situations described above. I.e. in no way will App B's resources, like cookies or other local data, be used.
 
=== Motivation ===
 
There are both benefits and downsides to this approach. The downside is that if the user interacts with the same website through several apps, he/she will have to log in in every app. Likewise, if a website wants to store data locally, and the user interacts with this website in several apps, the data will end up getting duplicated in each app which could be a problem if it's a large amount of data.
 
The main benefit of this approach is that it's a more stable model. There is no way that several apps could interact with each other through a 3rd party website in unexpected ways such that installing an app causes another app to stop working. When an app is uninstalled there is no way that data for another app could be lost, or that another app will stop working due to functional dependence of the uninstalled app.
 
There are also large security benefits. A user can safely use his AwesomeSocial app to log in to facebook without having to worry that the SketchGame app can mount any types of attack for getting at the users facebook data by exploiting bugs or other shortcomings in the facebook website.
 
There are also good privacy benefits. The user can safely install the PoliticalPartyPlus app without having to worry that MegaCorpEmployeeApp will be able to detect that the app was installed or what data it has created.
 
=== Sandboxed Permissions ===
 
And just like website data is sandboxed per app, so are permission grants. If App A loads a page from http://maps.google.com and that page requests to use geolocation and the user says "yes, and remember this decision for all times", this only means that http://maps.google.com has access to geolocation withing App A. If App B then opens http://maps.google.com, that page won't have access to geolocation unless the user grants that permission again.
 
And just like in the normal browser, permissions are separated by origin. This means that if App A is granted permission to use Geolocation, this does not mean that all origins running in App A has permission to use Geolocation. If App A opens an <iframe> to http://maps.google.com, that website still has to ask the user for permission before geolocation access is granted.
 
=== browserContent flag ===
 
To additionally secure applications that open a large set of URLs, such as browsers, we have added a "browserContent flag". The browserContent flag allows each app to have not one, but two sandboxes, one for the app itself, and one for any "web content" that it opens. For example:
 
Say that the MyBrowser app is loaded from the https://mybrowser.com domain. This is the domain where the scripts and resources which comprises the browser app itself.
 
If a page in this app creates a <iframe mozbrowser> we will inside this iframe always use a separate sandbox than the sandbox used by the app. I.e. if this iframe is navigated to https://mybrowser.com, this will result in different cookies being used inside the <iframe mozbrowser>. Likewise the contents inside the <iframe mozbrowser> will see different IndexedDB and localStorage databases than when opened by the app itself, outside of the <iframe mozbrowser>.
 
This also applies if the MyBrowser app wants to create integration with for example google maps to implement location-based browsing. If the app opens an <iframe> to http://maps.google.com, that will open an iframe which will receive a set of cookies for the http://maps.google.com website. If the user then navigates inside web content area, i.e. inside the <iframe mozbrowser>, to http://maps.google.com, this will use different cookies and different permissions than the browser-integration iframe.
 
Another example where this is useful is in a yelp-like app. Yelp has the ability to visit a restaurants website directly in the app. By using <iframe mozbrowser> to open the restaurant website, the yelp app ensures that the restaurant website can't contain an <iframe> pointing back to http://yelp.com. If it does, it will only receive the yelp website, rather than the yelp app. So there is no way that the restaurant website can mount an attack against the app since the contained yelp website won't share any permissions or data with the yelp app itself.
 
== Apps can run content from many domains ==
 
As has been discussed above, an app can always contain content from multiple domains. This is exactly like how a website today can create an <iframe> pointing to a different domain.
 
But just like for websites today, a webpage which contains an <iframe> pointing to a different origin can't reach into that iframe and modify or touch the objects there. And like with normal websites, permissions are separated by origin, meaning that just because a permission is granted to an app, doesn't mean that any <iframe>s that that app opens has access to the same permissions.
 
== Extended permissions ==
 
Applications can be granted additional privileges on top of the ones granted to normal websites. By default an application has no permissions on top of the ones normal webpages have. In order to get additional permissions, the first step is for the app to enumerate the additional permissions it wants in the application manifest.
 
For each additional permission that an app wants, the manifest has to explicitly enumerate that permission along with a human-readable description of why the app wants access to that permission. This description will be surfaced at various points in the UI, and is also used when the app is reviewed.
 
An example of a fragment of a manifest:
 
permissions: {
browser: {
description: "To enable showing web pages";
};
"wifi-information": {
description: "To alert you about unencrypted wifi networks in your area";
}
}
 
=== Privileged-app-only permissions ===
 
Some permissions are sensitive enough that we don't want to just hand them to any app. For example a permission which enables pages to read or modify pictures from the users picture folder is very sensitive. For such an API we in addition to requiring the app to enumerate the permission in the app manifest, require that the app is a "Privileged App". See details about this in the section for Privileged Apps below.
 
=== Prompting ===
 
Just because a permission is enumerated in the manifest doesn't mean that an app will be automatically granted that permission at time of installation. For many APIs, like the wifi-information API, enumerating the permission in the manifest simply means that the app can attempt to use it. When used, the user will be prompted and asked if it's ok to grant the permission to the app. During this prompt, the description provided in the manifest will be displayed to the user. However it will be displayed in such a way that it is clear that the description comes from the app developer, and not from B2G itself.
 
=== Implicit access ===
 
Not all permissions will result in the user getting prompted when the permission is first used. In some cases it's very hard to describe to the user what granting the permission means.
 
In this situation we can't rely on the user to make the security decision. Instead we will have to rely on a technical code-review of the app before it is published in a store to ensure that the app doesn't do anything it shouldn't with the extended permission. See the "Trusted apps" section below for how this works.
 
In this situation access is granted implicitly at install time.
 
''Open question'': Should we enable users looking at the list of prompted and implicit permissions at the time of installation?
 
=== <code>access</code> property ===
 
For some APIs there is an additional "access" property which allows specifying if the app wants read, write or create access. This looks like:
 
permissions: {
contacts: {
description: "To find friends to send your awesome high-scores to.";
access: "readwrite";
};
}
 
Valid values for the access property are:
* "readonly": Ability to read data and be notified about changes to data. No ability to write data at all.
* "createonly": Ability to create new data. Not read, modify any existing data.
* "readcreate": Ability to read existing data as well as create new data. No ability to modify existing data.
* "readwrite": Full ability to read and modify any data.
 
In the above, deleting existing data counts as modifying it.
 
These access levels aren't surfaced to the user at all. They are only there as a level of protection and to help during the code review of the app to determine what they need to look for while reviewing an app. So for example in an app which is requesting "createonly" access to the Contacts API doesn't have to be reviewed to see if it is doing anything unexpected with read contacts information (such as save it to the server without first asking the user), since the app can't ever read contact information.
 
But even for an app which requests "readwrite" access to the Contacts API, as soon as the app performs a reading or writing operation B2G will prompt the user about permitting access, and if the user grants access, full read and write access will be granted. There is no need for additional prompts assuming that the user checks the "remember this decision" checkbox.
 
''Open Question'': We could surface in the prompt which of the above four types are being requested. It wouldn't increase the number of prompts that we have, but it would mean having to deal with what happens if the access changes for example from "readonly" to "readcreate" during an update.
 
== Delivery mechanisms ==
 
B2G will support two formats for distributing apps, "hosted" and "packaged". Hosted apps work much like websites do today in that the resources for the app are located on a webserver and loaded through http. These can be cached for faster startup, but they still generally are delivered a lot like a normal website.
 
Packaged apps are delivered as a .zip file which contains the resources that the app consists of.
 
Generally speaking, it's entirely up to the app developer to choose between hosted or packaged apps. There are no differences as far as capabilities goes.
 
However, there are some APIs that are only available to "Privileged Apps", which currently requires the app to be packaged due to signing requirements. See section below for Privileged apps.
 
=== Hosted apps ===
 
A hosted app consists solely of an [http://mozilla.github.com/webapps-spec/ application manifest] file on the developer's web server. Often the manifest will also point to an appcache manifest which allows an app to be cashed for faster startup and to enable offline usage, but otherwise doesn't affect the app at all.
 
From a security point of view, hosted apps work very much like normal websites. When a hosted app is loaded, the URL of the loaded pages are the normal URLs that those pages have on their web server. So to link to a specific page or resource in the app, the same URL is used as when linking to that page or URL on the website.
 
This doesn't change the fact that hosted apps, like all apps, are subject to the application sandbox described above.
 
In order to secure that an app really wants to be installed as a web app we have to ensure that it's not possible to trick a website into hosting an application manifest. This is done by requiring that the manifest is served with a specific mime-type, "application/x-web-app-manifest+json". This restriction is relaxed when the manifest app, and thus the app manifest, is same-origin with the page that requested the app to be installed.
 
=== Packaged apps ===
 
The second distribution format that B2G will support is packaged apps. A packaged app consists of a normal zip file which contains both the manifest and the application resources. When a packaged app is installed, the zip file is downloaded and the manifest is read from a well-known location inside the zip file.
 
Unlike a hosted app, packaged apps doesn't have an obvious URL that their resources can be loaded from. The way to refer to a resource in a packaged app is by using the <code>app:</code> protocol. The format for a <code>app:</code> URL is as follows
 
<code>app://identifier/path/within/zipfile/file.html</code>
 
The <code>identifier</code> is a uuid generated at install time. This identifier will remain constant as long as the app is installed. (Eventually the identifier might become the ''home domain'' of the app, but we don't have such a concept yet).
 
Whenever a resource is loaded using the <code>app:</code> protocol, this will only allow loading resources from the zip file associated with the current app. I.e. if you specify an <code>identifier</code> for another app, it will behave exactly as if you specify an invalid identifier or an identifier for an app which isn't installed.
 
Relative links within <code>app:</code> works just like relative links within <code>http:</code>. Simply using a URL like &lt;img src="/images/picture.jpg"> will load the image named "images/picture.jpg" in the zip package. You can also use markup like &lt;a href="foo/bar.html"> to refer to a page relative the current page.
 
''Open question'': We probably need to allow linking to an app:// page. However we could forbid putting an app:// page in an &lt;iframe>. Other than by other app:// pages of course.
 
One important thing to note about this is that the app protocol doesn't have a concept of a domain. In other words, packaged apps aren't same-origin with any "normal" websites. This is because we don't know the home domain of the developers or the app. We only know which store was used to install the app.
 
A result of this is that any time XMLHttpRequest is used to read data from a website, it's considered a cross-origin read and so the website has to support CORS. Eventually we'll want to enable packaged apps having a home domain, but that's not yet supported.
 
Just like with hosted apps, we want to make sure that a hosting website can't be tricked into hosting a app package. The risk is fairly low even if that could happen since even if the user got an app installed, as mentioned above, that app won't be same-origin with the website that the package came from. However to be safe we still apply the same security restrictions as for hosted apps. I.e. the package has to be served with a specific MIME type, or has to be same-origin with the page installing the package.
 
More information about why we developed a packaged apps solution is available here: [[Apps/PackagingProposal]]
 
== Privileged apps ==
 
As mentioned in the "Extended privileges" section, some permissions are sensitive enough that we don't want just any webapp to get access to it. For example, the DeviceStorage API lets a website delete all the pictures in the user's "pictures folder". The API implementation does ask the user for permission before doing this, however we don't feel that it is enough protection for the user if the only thing standing behind the user and 10 years of lost pictures is a simple "do you want to allow this" dialog.
 
There are also some APIs that are too hard to explain to the user what consequences approving a certain permission would have, such as raw TCP socket access. For these we can't rely on users making well informed choices and so we need an alternative solution.
 
To support this we are also supporting a security model where the store takes on the responsibility of ensuring that an app won't behave maliciously with the permissions that it is granted. So for example the store takes on the responsibility of ensuring that an app won't use TCP sockets to scan for data on internal networks and save it on the developers website. And the store makes sure that an app won't delete all the user's pictures even if the user says ok to granting the app permission to use the DeviceStorage API. At least not without making it abundantly clear to the user that that is what will happen, and gives the user plenty of room for error.
 
Several mechanisms are used to enable to store to do this:
 
* The app will have to be reviewed by the store. Including reviewing all of the code that makes up the app.
* The app will be signed by the store to ensure that hacking the store website doesn't allow a hacker to install arbitrary content on users devices.
* The app will use a CSP policy to harden the app itself against bugs which would allow an attacker to inject code into the app. This will also make reviewing the app easier.
 
=== App Review ===
 
The store is responsible for reviewing the app to ensure that it doesn't do anything dangerous with the permissions it is granted.
 
Since the OpenWebApps API allows any website to become a store, only stores approved by B2G will be allowed to install Privileged apps. Our goal is that multiple stores will become approved for installing privileged app, but given how much responsibility is put on the store, we need to ensure that we put agreements in place to protect users before approving a store for being allowed to install privileged apps.
 
=== App Signing ===
 
''Definition of the signing format goes here. Brian Smith is working on this.''
 
=== Default CSP policy ===
 
The CSP policy applied to all trusted apps is:
 
<code>default-src *; script-src 'self'; object-src 'none'; style-src 'self'</code>
 
This puts the following restrictions on pages in privileged apps:
 
* Scripts can only be loaded from the package.
* Scripts can not use data:-URIs
* Inline scripts can not be used
* eval() can not be used. Neither can eval-like functions like setTimeout or "new Function". setTimeout can still be used as long as the first argument is a Function object rather than a string.
* onXXX attributes can't be used in the markup of pages. You can still write javascript code like <code>myelement.onXXX = someFunction;</code> as long as you don't assign onXXX to a string, but rather to a Function object.
* <object>, <embed> and <applet> are fully disabled. In other words, plugins won't work at all. Including flash.
* CSS can only be loaded from the package. Inline CSS is however allowed.
 
This does not restrict any of the following:
 
* <code>&lt;iframe>s</code> can still point to any URL.
* Images can still be loaded from anywhere. Including when loaded using an <code>&lt;img></code> element, when using CSS background images or when using other types of CSS images.
* Media (audio and video) can still be loaded from anywhere.
* Network connections can still be opened anywhere using data-centric APIs like <code>XMLHttpRequest</code> or <code>WebSocket</code>.
 
There is no way for privileged apps to relax this policy. However we may in the future add the ability for packaged apps to define their own CSP policies, in which case that would allow apps to apply more restrictive policies. However such policies would be merged with the above policy which means that it still wouldn't allow the app to relax the policy.
 
== Updates ==
 
A lot of the update model is still being defined. Requirements are being collected here at [[Gaia/System/Updates]]
 
== permission manager ==
 
== Data management ==
 
appid/browserContent flag in B2G
separate profiles on desktop/android
 
== Process sandboxes ==
==Out of scope for 1.0==
Confirm
717
edits

Navigation menu