Firefox Lockdown


This is part of an experiment to use Linux as a kiosk system. 'Kiosk System' can mean a couple of things, but here we assume that it's a computer that runs just one application - a web browser - and does not allow the user to do anything else but use that browser. That way, the computer can be left unattended, e.g. in public places (public libraries, cyber cafes, ... ) as a kiosk-type Internet PC.

In this article, we investigate some of the measures that can be taken to let users use Firefox in a kiosk environment - i.e. in a customized configuration with limited functionality. You want the users to be able to browse the web, but you might want to set connection settings to always use your proxy server (where you might implement content filtering), you'll probably set a default home page and maybe a predefined set of Bookmarks, and, as this computer will be unattended and be used by multiple users, you don't want users to change your defaults, install extensions, or use firefox in an inappropriate way, e.g. as a file browser to view files on your system. You're looking for some sort of kiosk mode or "lockdown" configuration. Here are a few steps you can take.
And of course we look into ways to make it 'low maintenance'.


Assumptions, Prerequisites and System requirements

Locking down firefox only makes sense if the rest of the system has been locked down as well. Why would you try to lock the firefox configuration if any user can start a shell, run a text editor, and overwrite your configuration?
So, you probably want to implement this on a "minimalistic desktop configuration" on a locked down system.

Firefox expects to have write access to ~/.mozilla and certain files therein, such as the (user) prefs.js preference file. It will fail with an "Another instance of firefox is already running" error if it does not have this write access (it assumes the files are locked by another firefox process).
So, while you can pre-configure firefox and limit the user's ability to change the configuration, you can not (to my knowledge) completely prevent the user from making changes. You may need to implement some sort of "deepfreeze" mechanism, eg you might want to delete all files in the user's home (or at least in ~/.mozilla) and replace them with your with every new X session. X and most window managers provide startup scripts where you can implement the relevant delete & copy, rsync or ln (replace files by links to a readonly file/directory) statements.
See this for some ideas on how to approach this.

Step 1: control where firefox gets its configuration from

review /usr/share/firefox/greprefs/all.js and make sure the following entries are present. Add them if they're not:


	pref("general.config.filename", "firefox.cfg");		// filename for the general configuration file
	pref('general.config.obscure_value', 0); 		// encryptie voor firefox.cfg afzetten
  

Step 2: Modify the general configuration file

/usr/lib/firefox/firefox.cfg is the configuration file that sets system-wide configuration and default preferenses for firefox. Note that the filename can be modified (re. Step 1 - /usr/share/firefox/greprefs/all.js) but the path can not. The file is expected to live in the same directory as the firefox executable (/usr/lib/firefox/firefox-bin). However, it can be replaced by a link to a file in another location, eg /etc/kiosk/firefox/firefox.cfg

The interesting part here is that you can lock preferences : you set a default, and by locking it, the user will be unable to modify it - even with write access to his/her ~/.mozilla directory. So the challenge here is to list all possible preferences (that you want locked and/or defaulted), and set them. Here are some examples. Look at your own ~/.mozilla/firefox/(profile)/prefs.js for more. Dont forget to replace user_pref by lockPref if you copy from prefs.js

	// systemwide configuration file for Firefox
	//
	lockPref("browser.startup.homepage", "http://192.168.1.1/opac/home.html");
	lockPref("pref.browser.homepage?disable_button.current_page", true);
	//
	// Network and Proxy
	lockPref("network.proxy.http", "192.168.1.1");
	lockPref("network.proxy.http_port", 3128);
	lockPref("network.proxy.no_proxies_on", "localhost, 127.0.0.1, 192.168.1.0/24");
	lockPref("network.proxy.share_proxy_settings", true);
	//
	// History and Privacy
	lockPref("privacy.sanitize.promptOnSanitize", false);
	lockPref("privacy.sanitize.sanitizeOnShutdown", true);
	lockPref("network.cookie.enableForCurrentSessionOnly", true);
	//
	// disable undesirable protocols
	lockPref("network.protocol-handler.external.snews", false);
	lockPref("network.protocol-handler.external.news", false);
	lockPref("network.protocol-handler.external.irc", false);
	lockPref("network.protocol-handler.external.mail", false);
	lockPref("network.protocol-handler.external.mailto", false);
	//
	[...]
  

In this step, you've set (and locked) every item that can be configured in the Edit:Preferences menu and the about:config page.

Step 2bis: Mission Control - a networked global configuration file

With /usr/lib/firefox/firefox.cfg, you can set a global configuration for 1 computer, so to implement it on multiple machines, you'd need to copy it to each machine. This can be done by means of a customized .deb package on a local repository / web server, a rsync operation with a remote server, a wget job, etc - or by hand.

However, Mozilla's "Mission Control" provides a mechanism to implement a centralised, server-based configuration that is implemented every time firefox starts. This gives you both centralised management and flexibility - more so than copying the config file by hand or in scheduled / startup jobs. The principle is that the global config file resides on a webserver as a javascript file, and is referenced by the local firefox.cfg file. Like so :

/usr/share/firefox/greprefs/all.js
defines the global configuration file, as above
/usr/lib/firefox/firefox.cfg
contains (at least) the following settings:
		lockPref("autoadmin.global_config_url","http://yourdomain.com/autoadmin.js"); 	//required 
		lockPref("autoadmin.append_emailaddr",false);					//optional
		
So the configuration is deferred to the script 'autoadmin.js' on a web server
http://yourdomain.com/autoadmin.js
contains the preferences you want to set (and possibly lock) - exactly as /usr/lib/firefox/firefox.cfg would on a local system.

Unfortunately, I haven,'t been able (yet ?) to get this to work, and I don't yet know why (a bug in the Mission Control system or a bug in my setup ?). If "Mission Control" doesn't work for you, you might try to mimic it by means of a init / X / fluxbox startup script that copies the configuration file in question before the user is presented with a graphical desktop, and thus at least every time the user starts an X session. Or you just replace the new config file by hand whenever you've made changes to your global config.

Step 3 - Controlling the user interface

So far, we've used firefox.cfg (or autoadmin.js) to control the browser's behaviour. By locking down preferences, we've also modified the apperance of the user interface, eg. we can disable certain buttons / input fields / ... that can be used to edit those preferences. However, the user still has access to al kinds of tools and settings thhrough the menu bar, the toolbars, and so on. If you want that disabled as well, you need to edit the appearance of the user interface.

The apperance of the user interface is stored in ~/.mozilla/firefox/(profile)/localstore.rdf. The easiest way to edit it is to run firefox, modify it's appearance (hide menubar, hide bookmark toolbar ...), then close it again. Make a copy of ~/.mozilla/firefox/(profile)/localstore.rdf and copy this over to other machines where you want the same user interface.

You can copy it straight into the target user(s) firefox profile, or you can save a copy somewhere safe (a directory owned by root, s.a. /etc or /usr/share) and create a link to it from the user's firefox profile. Make sure that users have read access !

This step has enabled you to remove :

What's left is the menu bar. Apparently this can not be modified from the Firefox interface itself. However, you can edit the userChrome.css in the user's profile folder to remove menu items from it. See further : Hacks and Workarounds.

After this step + the modifications to userChrome, you have a browser that looks like this. The only controlls that are still visible, are the window title bar (property of the window manager), and a menu bar without menu items. Given that it is meant as a viewer/interface for a web application, and assuming that the application itself provides sufficient functionality for navigation, this is exactly what we want. For other scenarios, you might want to customize userChrome.css further to allow certain actions, or provide access to navigation buttons.
fluxbox and firefox as an online public catalogue for the Antwerp Public Library

Step 3 bis - Controlling the user interface through Mission Control

Since autoadmin.js is javascript, it can contain statements that control the userinterface, to the extend that the user interface can be controlled through javascript. Mission Control provides Program Interfaces that can be used to control and modify the browser even more than generic javascript can.

Note to self : This needs a closer look

Step 4 - Controlling the Keyboard

The modifications to the browser UI are, essentially, cosmetic : we've hidden stuff, but the underlying functionality is not gone. Although this will be cripling to most user, a knowledgable user van still use Firefox keyboard shortcuts to bring up pages through "Open Location" or "Web Search". If you want the user to stick inside your web application, that is not what you want.

Firefox provides preferences (that you can use in firefox.cfg) tp controll some keyboard behavior.

("ui.key.accelKey", INTEGER)
The accelerator key is the key that 'makes' the keybord shortcut. Usually it's the Ctrl key, sometimes (Unix) it's Alt. so you have to use the numbers, which are 17 for control, 18 for alt, 224 for meta (or command on Mac). If you could disable this key (by setting the INTEGER value to 0, -1, or some random number, you'd effectively disable all keyboard shortcuts, but apparently that isn't working.
("ui.key.menuAccessKey", 0)
The Menu Access Key is the key that makes the menu shortcuts work. Setting it to 0 disables it (possibly combined with "ui.key.accelKey"), in that eg. Ctrl+F to Open the File menu will stop working. However, shortcuts to (some ?) submenu items remain functional, eg the Web Search.
lockPref("ui.key.generalAccessKey", -1);
lockPref("ui.key.chromeAccess",0);
According to Mozillazine, this combination should disable key access to "chrome" (the user interface) but I haven't been able to make it actually stop opening the "Open Location" "Print" or "Web Search" dialogs.

More elaborate info on key bindings : Mozilla Customizing : Keys

Additionaly, it would be interesting iof we cound control Function Keys, although this is not critical, as they're quite harmless in Firefox :

So, we can achieve some serious lockdown with some rather minor configuration. However, some issues still need to be dealt with, and apparently there are no easily configurable files to achieve that. On to the more serious stuff ...

Extensions ?

In addition to the measures described in this article, you might consider installing some of the Firefox extensions to implement certain kiosk-like features. Candidates : autohide, inactivity reset, and single window. These extensions allow mozilla to open in fullscreen mode, clear user information, and to only use one window. I haven't tried them.

Reproduce it

To reproduce a locked down firefox configuration, you must create customized configuration files, e.g. by running firefox on a baseline system and customize it, then collect all configuration files mentioned here. Some files may require additional editing. Your collection of customized configuration files must then be applied to other computers.

It turns out that simply writing those files to the user home directory does not always work, because firefox apparently overwrites them, and making them readonly causes firefox to fail. A workaround is to collect the files on a 2nd location (eg in /usr/share/kiosk or on a network server), then rsync them to the user home.

This also provides a 'deepfreeze' mechanism : you can let the rsync run at startup (init script), at given intervals (scheduled job, cron), and so on. This is also useful to roll out newer versions of your lockdown configuration : dump the newer files in the appropriate location, and let the cron job or startup script do the rest.

Bonus : Thunderbird Email Lockdown

Should you ever need it : Thunderbird email client can be configured / controlled in pretty much the same way as Firefox

References

Kiosk Setup, David Collie
David Collie, Kiosk Setup, a more complete, production environment grade package for a Web Browser Kiosk. Also available as a live CD.
background information and documentation to the firefox lockdown applied in David Collie's Kiosk Setup
The boothbox project, home of David Collie's implementation, at sourceforge
Mozilla Firefox Mission Control / AutoAdmin
Documentation about and other implementations of Netscape Mission Control / Mozilla AutoAdmin :
Firefox Customization and Configuration
Mozilla Customization, Mozilla.org
an extensive list of configurable firefox settings
Linux Kiosk Systems
a few other approaches to Kiosk systems based on Linux

Koen Noens
December 2006
Partially rewritten July 2007