Who should read this document?
Developers, security folk, anyone else who's keen to know about Firefox Security.
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 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.
Wrappers - Wrappers protect extensions from untrusted content by providing safeguards and enforcing basic security rules such as the Same Origin Policy.
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 in detail here.
Developers should familiarize themselves with common security pitfalls associated with the technologies they're working with. Web devs should know about XSS and CSRF, if you're writing in C++, you should know about buffer overflows, format string vulnerabilities, etc
Code which runs in Firefox needs to prevent external code (ie 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.
Under norrnal 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, where 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).
Watch out for the following issues when dealing with URIs:
- If you're 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 it's checks) whereas other forms may not be.
- Check your schemes; only accept URIs with schemes you expect.
- Watch out for psuedoschemes - in security checks it's the inner URI that's significant (e.g. jar:http://example.com - http://example.com is the relevant part).
Before you load anything:
- Check 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.
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.