Who should read this document?
Developers, security folk, anyone else who's keen to know about Firefox Security.
Definitions
Content - Something (most commonly script) loaded from an untrusted source (e.g., a web page). In security discussions 'content' can refer to the set of restricted privileges made available to scripts in web content.
Chrome - Something pertaining to the browser (as oppsed to web content). In security discussions, this most commonly refers to a set of privileges which allows code to do everything (unlike web content, which is restricted).
DocShell - An object that hosts documents. A docshell is responsible for initiating the loading of content from a uri, creating the content viewer and hooking it up to the incoming content. There is a docshell associated with every window (tab) or frame.
Principal - A security context. On the web, this is typically a combination of scheme, host, and port.
Same-Origin Policy - A policy which prevents a document or script loaded from one origin accessing properties of a document from another origin.
Sandbox - An object that allows you to evaluate JavaScript code with restricted privileges. Code evaluated in a sandbox will have the same permission as if it was running in a 'normal' web page.
Wrappers - Wrappers protect extensions from untrusted content by providing safeguards and enforcing basic security rules such as the Same Origin Policy.
Assumptions
This document assumes some knowledge of security principles, common vulnerabilities, and attack techniques. Where concepts are mentioned, reference will be made to external resources that can provide further information on these concepts rather than outlining them here in detail.
Developers should familiarize themselves with common security pitfalls associated with the technologies they are working with. Web develpers should know about XSS and CSRF. If you are writing in C++, you should also know about buffer overflows, format string vulnerabilities, etc.
Goals
Code that runs in Firefox needs to prevent external code (i.e., running in a web page) from:
- Running with Chrome privileges
- Gaining file system access
- Stealing credentials
- Accessing the user's personal data without their permission
- Spoofing a trusted page (such as a banking site)
- Crashing Firefox, or causing it to become unusable
Note that we cannot protect the user from native code that they have downloaded and explicitly run.
Front end
- Normally, content can't get a reference to chrome objects.
- XSS from content to chrome is a bad thing; chrome has, essentially, all the privileges of the local user account running Firefox. This could result in remote attackers executing code, silently installing malware (keyloggers, etc.), reading the contents of the password manager, etc.
- Care is needed around use of untrusted data in XUL and HTML UI elements; it's common to see the use of innerHTML or similar when safer alternatives exist (e.g., createTextNode).
- One important difference between writing web content and chrome code is that in the latter, iframes have chrome privileges by default. If this is not desirable (and it probably isn't) you'll want to explicitly specify it's for content -- e.g., iframe.setAttribute("type", "content").
General
Security checks
Under normal circumstances, when content is loaded the browser enforces the Same Origin policy, preventing documents from different domains from interfering with each other.
If you are in a situation when you are loading web content from chrome code and you wish to perform similar checks it is recommended, wherever possible, to use the same mechanisms. Ensure you consult the documentation on principals and how security checks are performed before attempting to implement your own checks -- duplicating this functionality is fraught with danger. In situations where, for some reason, you must deal with URLs directly there are a number of pitfalls you should be aware of (see the URIs section below).
URIs
Watch out for the following issues when dealing with URIs:
- If you are performing operations on URIs, ensure you use nsIURI directly rather than ASCII hostnames (e.g., from getASCIIHost -- which is essentially only intended for display); this is because nsIURI is guaranteed to be canonical (notice nsIPrincipal takes nsIURIs for its checks) whereas other forms may not be.
- Check your schemes; only accept URIs with schemes you expect.
- Watch out for pseudoschemes -- in security checks it is the inner URI that is significant (e.g., jar:http://example.com -- http://example.com is the relevant part).
- Before you load anything:
- Check if you're allowed to; both nsIScriptSecurityManager and nsIPrincipal provide means of checking whether a resource is safe to load -- always use these. Also, see ContentPolicy.shouldLoad.
- Set the referer correctly when loading stuff at a web page's request or when following a link, but set no referer when loading a bookmark.
Sandboxes
Sandboxes should be used to evaluate JavaScript in Chrome code unless you explicitly need to run with Chrome privileges (and completely trust the contents of the script).
To create and use a sandbox:
// create new sandbox instance var mySandbox = new Components.utils.Sandbox("http://www.example.com/"); mySandbox.y = 5; // insert property 'y' with value 5 into global scope. var result = Components.utils.evalInSandbox("x = y + 2; x + 3", mySandbox); // result is 10, mySandbox.x is now 7
Objects inserted into a sandbox do not carry their privileges into the sandbox.
However, any function that comes out of a sandbox will execute with Chrome privileges.
So for the code:
var s = new Components.utils.Sandbox(url); var x = Components.utils.evalInSandbox(untrusted_code, s);
Any method calls on x are unsafe, including the use of == which when evaluated will call the x.valueOf() method.
Interactions with content DOM
Firefox relies on wrappers to provide 'safe' representations of objects from one context in another (e.g., chrome from content and vice versa). In simple terms, wrappers can be thought of as filtering proxies which enforce the rules on how content and script from different principals may interact. For example, if a chrome object is exported to web content it will be wrapped in a ChromeObjectWrapper; this ensures that only the properties which are supposed to be exposed to web content (there's a whitelist in the __exposedProps__ property) can be accessed.
Whilst these wrappers provide a good level of protection against accidental problems, there are some things to be aware of. In particular, take care when using wrappedJSObject on content objects from chrome code (for more information on safely accessing content DOM from chrome, refer to this document).
More information on wrappers can be found in this article.
Chrome JS Dangerous functions
Avoid using eval or setTimeout(string, time) and other related functions if at all possible.
Further Reading:
- https://developer.mozilla.org/en-US/docs/Safely_accessing_content_DOM_from_chrome
- https://developer.mozilla.org/en-US/docs/XPConnect_wrappers
- https://developer.mozilla.org/en-US/docs/XPConnect_security_membranes
- http://blog.mozilla.org/gabor/2012/04/18/security-wrappers-part-1/
- Linked from the above, but worth noting as well: