April 12, 2010

Build a Secure Linux Kiosk OS

The original requirement was for a collection of 4 touchscreen information stands in a NHS hospital (providing information such as maps/”You are Here”, patient information etc.).  It was absolutely critical that the system could not be hacked and that content was limited. The kiosks were to serve information from a local web server but some of the content being provided was from pages on the Internet. To that end, a further requirement was locking access to sites, only sites and content in a safe “whitelist” were to be served, making it necessary to block attempts to retrieve any other Internet content.


NHS Touch Screen KioskA custom distribution of the Linux Operating System was built called KiOS (abbreviation for Kiosk Operating System).  KiOS is a custom distribution of Linux (based on SuSE / built using SuSE Studio) intended for usage in the Kiosk environment.  There are 2 variants, one for the clients and one for the server.  Rolling back in time, the solution “rough cut” was as follows:

  1. Content via web browser. Browser must not have any controls (file menu, address bar, right click etc.), downloads or similar.
  2. The Kiosk must not allow access to the underlying operating system and the browser must not be closed.
  3. The Kiosk will connect to the network via DHCP.
  4. The Server will always assign the same IP address to the same MAC (allowing for “you are here” to function).
  5. The Server runs a whitelist of allowed sites, requests to any other content are denied.
  6. The Server acts as a web proxy to cater for the “Internet Down” scenario.


The KiOS Operating System (for clients)

The base distribution began as follows:

  1. KiOS was built using SuSE Studio ( http://www.susestudio.com ).
  2. A base template “JeOS” (Just enough Operating System) was used.
  3. X11 was added as a package. Note that NO WINDOW MANAGER was used. This gives an advantage in that no window manager keyboard shortcuts are available/no update manager alerts are given etc.
  4. The Flash player was also added (optional and not necessarily desired in every scenario).
  5. The firewall was setup to block ALL incoming requests. NO PORTS are open.
  6. The OS was set to load at run level 3 (normal non-graphical console).

The KiOS disk image is written to a USB pendrive. The system is set to boot off USB. No hard disk is required. This also benefits in that the “worst case scenario” typically requires just a reboot. If that fails, the pendrive can be removed and inspected or simply re-flashed. The pendrive in the real kiosk is locked away behind a secure panel.

The first time the OS boots it performs setup (network, graphics etc.). We then run a script to secure the GRUB boot menu and make the “default” option boot immediately:

if [ -f /etc/init.d/suse_studio_firstboot ]
# Lets protect our lovely grub...
echo "Running KiOS first boot script..."
cat /boot/grub/menu.lst | grep -v timeout > /boot/grub/menu.tmp
cat /home/kiosk/menu.lst /boot/grub/menu.tmp > /boot/grub/menu.new
mv /boot/grub/menu.lst /boot/grub/menu.old
mv /boot/grub/menu.new /boot/grub/menu.lst

In short, remove the standard timeout of 10 seconds. Then paste the contents of a second file at the start of the menu. The second file contains the following:

timeout 0
password --md5 <hash>

Effectively hiding the menu by default, causing immediate boot to the default option, and (worst case) if someone does intercept the menu a password is required to edit any options.

Also, on first boot, a number of files are overlaid into the operating system:

/home/kiosk/.bashrc contains a simple “exec startx”. EXEC replaces the shell. Thus, if X dies, the kiosk user is logged out.
/home/kiosk/.xinitrc starts Opera in Kiosk mode with a number of options. Namely – full screen, no keyboard shortcuts, no menu, no toolbar, no address bar, no saving, no printing, no downloading, no right click/context menu, a reset flag (if the kiosk is left unattended, return to the home page after a given interval), no “mailto” links, no history, clear the cache on exit, no ctrl-alt-del etc.
/home/kiosk/opera.tar.gz is restored to /home/kiosk/ creationg a directory called .opera with one file – opera6.ini – containing other Opera preferences to lock down the web browser ( for more information see http://www.opera.com/support/mastering/kiosk/ ). This also has a knock on effect in that it tricks Opera into believing this is not the first execution – the EULA does not appear as one would normally expect.
A new version of inittab is copied over to /etc/ that forces run level 3, turns off all TTYS (ctrl-alt-F1 etc.), and automatically logs in the kiosk user. This combination now means that if Opera is killed, X dies, user is logged out and re-logged in automatically (i.e., the browser simply reappears!). Ditto if Ctrl-Alt-Backspace is hit twice (this was left in as a tidy way of restarting Opera if it crashes).
A replacement xinitrc.common is copied to /etc/X11/xinit/ – the only difference being the suppression of an error message (by default, on login, a dialog appears complaining that no window manager has been found).

The user can still Ctrl-Alt-F1 (etc.) but the terminals are all dead aside from the one running Opera. Anything killing Opera results in a logout/login/startx/start opera. In the real world – the keyboard on the kiosk has no Ctrl or F keys – but, it is still better to cater for every eventuality (keyboard!).

KiOS without a Server

If KiOS is to be used in an environment without a server Opera can be configured to handle the whitelist/blacklist:

  1. Exit Opera
  2. Define a filter file in opera:config
  3. Create a filter file if it does not exist already
  4. Make an [exclude] section listing the URLs to block
  5. Make an [include] section listing the URLs to allow
  6. Restart Opera

Example limiting access to just one site:

prioritize excludelist=0

Dealing with the USB stick and what happens if SuSE remove the Studio service?

The raw disk image is written to the USB stick with the following command:

sudo dd if=/home/garyr/Desktop/KioS/KiOS.i686-1.1.11.raw of=/dev/sdb bs=4k

If the USB will not boot:

umount /dev/sdb1
fdisk /dev/sdb
\tp     «--- print partition table
\ta     «--- activate partition (bootable)
\t1     «--- partition 1 is bootable
\tw     «--- write changes to partition table

The disk image can be modified without using Studio as follows:

mount -oloop,offset=32256 discimage.raw /mnt/

Key File Contents


exec startx


opera -kioskmode -nowin -resetonexit -nosplash -nosave -noprint -nomenu -nomaillinks
-nomail -nokeys -nocontextmenu -kioskresetstation -nodownload

inittab (selected entries only):

1:2345:respawn:/sbin/mingetty --noclear --autologin kiosk tty1
#2:2345:respawn:/sbin/mingetty tty2
#3:2345:respawn:/sbin/mingetty tty3
#4:2345:respawn:/sbin/mingetty tty4
#5:2345:respawn:/sbin/mingetty tty5
#6:2345:respawn:/sbin/mingetty tty6

xinitrc.common (basically delete a block):

# Error, no Window Manager found.  Normally the exit
# raises the fallback trap of the sourcing script.
# ...error dialogue removed leaving just:
exit 1

menu.lst and first boot:

See earlier

opera6.ini (selected entries only, proxy settings also go in here):

[User Prefs]
Language File=/usr/share/opera/locale/en-GB/british.lng
Preferences Version=2
Has Restored MIME Flag=1
Trust Server Types=0
Check For New Opera=0
DevTools Splitter Position=500
History View Style=0
Open Page Next To Current=0
Last Used Auto Window Timeout=60
Enable Wand=0
Show Startup Dialog=0
Startup Type=2
Home URL=http://www.google.com
Ignore Target=1
Target Destination=3
Ignore Unrequested Popups=0
Keyboard Configuration=/usr/share/opera/ini/standard_keyboard.ini
Enable Gesture=0
Mouse Configuration=/usr/share/opera/ini/standard_mouse.ini
Window Cycle Type=0
Use Thumbnails in Window Cycle=0
Use Thumbnails in Tab Tooltips=1
Activate Tab On Close=0
Visited Pages=0
Accept Cookies Session Only=1
Enable Cookies=3
Toolbar Configuration=/home/kiosk/.opera/toolbar/standard_toolbar_1.ini
AddressBar Alignment=0
Accept License=1
Reading Plugins=0
[Disk Cache]
Empty On Exit=1
Images Expiry=18000
Other Expiry=18000
Docs Modification=1
Figs Modification=2
Other Modification=2
Go Home Time Out=60

Closing Notes for the Client

  • The host PC should be set to boot from USB!
  • The host PC should have a BIOS password to prevent changing of the boot order.
  • It may ultimately be worth disabling Ctrl-Alt all together.
  • Still need to investigate SysRq ( http://en.wikipedia.org/wiki/Magic_SysRq_key ) though on first inspection the only combination that works is Alt-SysRq-o to power down.
  • Navigation Issues. There is no home button, back/forward etc. In the initial application of KiOS this is not an issue as the web page being used will handle it. In other scenarios, a navigational IFRAME could be used or limited toolbar buttons re-enabled.
  • Customer did not want a screen saver kicking in, the screen stays on with “touch here to start”. This was fixed by adding “xset -dpms” and “xset s off” to the xinitrc before the Opera call.
  • Touch screen drivers. The package x11-input-evtouch was added to the build in SuSE Studio.

The KiOS Server Configuration

Broadly speaking, the steps involved were:

  • Setup the router (firewall, make it keep IPs per MAC address etc.).
  • Setup server OS including web server.
  • Write the kiosk client image to USB sticks.
  • Edit the USB client sticks setting the Homepage and the proxy settings:
Use HTTP=1
Use FTP=1
Use WAIS=1
Use Automatic Proxy Configuration=0
HTTP server=
HTTPS server=
FTP server=
Gopher server=
WAIS server=
Automatic Proxy Configuration URL=
Enable HTTP 1.1 for proxy=0
Use Proxy On Local Names Check=0
No Proxy Servers=
No Proxy Servers Check=0
  • We then setup Squid (the web proxy software) to run on its default port (3128).
  • Configure the white list/ACL using Squid so only sites stated are allowed:
  • You can do that in your squid.conf using an acl such as:
acl whitelist dstdomain "/etc/squid/whitelist"
http_access deny !whitelist

...and a whitelist that looks like...

  • Another option would be to use an acl with “dst (ip-address/netmask)” instead of “dstdomain (.linuxquestions.org)”. Modify to your needs,
    there are tons of other options described in the squid.conf comments.
  • Custom 404/redirect to HOME for sites not accessible.
  • Firewall Server OS except for port 80 (web) and 22 (ssh for remote admin – will require port forwarding in router – no other outside ports should be accessible).
  • Confirm all of this via both internal and external NMAP scans.
  • Deploy the content to the server.  Tweak as necessary.  Server should be only MAC with Internet access.  Everything else via proxy.
  • Check IP assignment in router, force it to stay the same always, and update the “where am I” configuration accordingly
  • Check squid logs to make sure clients are indeed going via proxy.