Hack 18. Digitally Sign Content
Content delivered to Firefox can request special privileges from the user. Normal Firefox content, whether it's HTML, XHTML or XUL, runs inside a sandbox that stops it from doing anything risky, such as modifying files stored on the local disk. This hack explains how to ask the user for permission to escape the sandbox. If permission is given, the content (usually scripts) can do whatever it likes. You can also arrange matters so that the user is never asked for permission [Hack #19] . 2.9.1. Get Oriented on Security ConceptsThe design ideas behind granting permission are trust and identity. If the web page content is to have full control over the browser, there must be trust between the browser user and the content creatortwo real, live people. Access to technical features is secondary to this human principle. In the conservative world of security, trust can be assured only if identity can be properly determined. Here are the identity constraints built into Firefox:
The Firefox user can drop these constraints if they so choose. When presented with information about a content maker, the user can tell Firefox to trust that content maker in the future. That puts identity information about the content maker in files in the user profile area. Firefox will always validate signed content, but it can do so silently if the user directs it to do so. Validating signed content is done automatically by Firefox. Making signed content is a task for a web site content creator. These identity constraints are supported by technologydigital certificates and digital signingand by a special sandbox-breaking API that only works when trust is in place. They also demand some old-fashioned paperwork. A real, live person called a Certificate Authority (CA) is required. Little of that infrastructure is obvious or meaningful to an end user confronted by a permission request, though. 2.9.2. Get Signing ToolsNetscape Security Services (NSS) is a technology that is part of the Mozilla source code used to make Firefox. NSS includes a small, separately downloadable program called signtool. Get it here: signtool can combine content (HTML, JavaScript, XUL, CSS, images, anything) with digital signatures by using certificates. signtool is incompatible with similar systems used in Netscape 4.x, Internet Explorer, and Java. It is good only for Mozilla-based browsers and other software systems that support it. signtool has some compatibility with Java, but a second tool called certtool (http://ftp.mozilla.org/pub/mozilla.org/security/nss/releases/) is also needed. Signing content is called object signing, which is different than signing a certificate. The result of object signing is a JAR file [Hack #86], which contains both content files and digital signature files. Signing content is a nuisance for technologists that just want to build something. Mozilla allows signing to occur in two separate ways. You can sign in a test environment, where it is easier to use, or you can sign in a published environment, where it is fully secure. 2.9.3. Sign Content for Test PurposesIn a test environment, two of the three identity requirements can be dropped. The browser user can be kept ignorant of the content maker. The browser user is thus unable to track down that person. That leaves only the requirement that the browser user explicitly grant permission to the content maker. To enable this weaker security arrangement:
In a test environment, both of these roles are likely to be taken by one developer. To create the special certificate, first create a certificate database. Then, make the special object-signing certificate and put it into the database: mkdir certs cd certs certutil -N -d . signtool -G ' special ' -p ' password ' -d . special is the name chosen for the new certificate. The password string should be whatever you typed in when certutil ran. Use single quotes on Linux/Unix to prevent shell reinterpretation. To tell Firefox it's OK to work with this certificate, use the following preference: signed.applets.codebase_principle_support /* set to true. Default = false */
You are now ready to sign your content. Suppose it's in the directory content, which is a sibling of the certs directory: cd .. signtool -d certs -k ' special ' -p ' password ' -Z result.jar content The file result.jar is all the signed content. Put it behind the web server and retrieve it with a URL, or with a jar: URL. jar: URLs are normally used for chrome packages [Hack #75], but you can put ordinary web site content in them, too. 2.9.4. Sign Content for PublicationIn a production environment, you must have a genuine digital certificate before you start. Suppose your organization's name is Acme, and the certificate comes from the CA Verisign, who gave it this short name: Acme Cert (Verisign). Once that certificate is in a handy certificate database [Hack #17], make your object-signing certificate based on it as follows: cd certs
signtool -G 'objcert' -k 'Acme Cert (Verisign)' -p ' Next, sign your content with it. This is the same as in the test environment, except this time we have a real certificate: cd ..
signtool -d certs -k 'objcert' -p ' Put the result.jar file on the web server as before. You're ready to go and don't need the special preference. 2.9.5. Do Something with Trusted ContentIf you've asked the browser user for trust, you must need it for some reason. There are two things you can do: you can sign an XPI file, and you can write scripts that break normal web scripting rules. If you sign an XPI file, that file can be installed into Firefox from any web site, provided that the user gives permission. Since an XPI file and JAR file have the same format, the signing procedure is also the same. The web site that delivers the XPI file does not need to be listed as an authoritative source of extensions or patches in this case. This sample JavaScript script requests all possible permissions and then runs some code that wouldn't work in a normal web page: function run( ) { // normal permissions to start with critical_section( ) // normal permissions again } // Might be a trusted function, depending on who calls it. function do_stuff( ) { var list = window.Components.classes; // try to access XPCOM } function critical_section( ) { // ask the user for permissions; should check return value as well netscape.security.PrivilegeManager.enablePrivilege( "UniversalBrowserRead" + " " + "UniversalXPConnect" + " " + "UniversalPreferencesRead" + " " + "UniversalPreferencesWrite" + " " + "CapabilityPreferencesAccess" + " " + "UniversalFileRead" + " " + "myCapability"); window.resizeTo(20,20); // make current window tiny - requires trust. do_stuff( ) // called with trust in place } // permissions will end when this function returns run( ) // do it The myCapability option is a custom capability class [Hack #20] . See http://www.mozilla.org/projects/security/components/signed-scripts.html for details on the meaning of all the options. |