In this post i will show an example on how to pratically realize a more secure web browsing environment exploiting some great Linux kernel features to create sandboxed environments for browsers. If you don’t know what i’m talking about and you haven’t yet done it, read the first part!

There are many tools in the wild to build the sandboxes using the features explained, some more user friendly, other more complex, some more complete, other more specific to one or few features.

After some tests and with the help of many friends from the Veteran Unix Admins group on facebook, the primary tool I’ve chosen to use is firejail.

Firejail is a great utility aiming to build sandboxes and it match almost perfectly our needs. With just a little bit of shell scripting, a little patch I have sent to firejail and a couple of other tools supported by firejail itself, we have all what is needed for our architecture.

As for the browser, we will use the worst one in terms of privacy, google chrome. Chrome has been chosen cause it’s the most fucking son of a bitch hard to make works as expected at least between the most diffuse browsers, and is a very commonly used one.

The Linux distribution over this post is focused is Devuan GNU/Linux, if you don’t use it, shame on you, but the commands and scripts should works on every deb based distro like Ubuntu, Debian and others. If you are in the rpm world, you will have to adapt things for you, or better, you should switch to Devuan too.

As explained in the precedent post, we will have 3 different level of browser isolation:

  • trusted 
  • secure
  • paranoid

so, let’s go

System preparation

As already said, we will use firejail, so, you need to install it. The already packaged version in Devuan is updates, so, if you use devuan, you can just do:

# apt-get update && apt-get install firejail

if you use another distro and your package manager show a version < of 0.9.42~rc2 you should compile and install it from the git upstream repository 

we will also need xpra and the dummy xorg driver and a little bit of python

# apt-get install xpra xserver-xorg-video-dummy python-opengl tor privoxy bridge-utils

I assume you already have a working Xorg, sudo and pulseaudio or working alsa config, chrome ( or the browser you will use ) installed.

3d accelleration should works too, but if you have issues with it, you can follow instruction in or try to use

Add 3 users to the system:

# groupadd -r fjtrusted
# useradd -r -s /bin/bash -g fjtrusted -G audio,video -d /home/trusted fjtrusted
# mkdir /home/trusted && chown fjtrusted.fjtrusted /home/trusted
# groupadd -r fjsecure
# useradd -r -s /bin/bash -g fjsecure -G audio -d /home/secure fjsecure
# mkdir /home/secure && chown fjsecure.fjsecure /home/secure
# groupadd -r fjparanoid
# useradd -r -s /bin/bash -g fjparanoid -d /home/paranoid fjparanoid
# mkdir /home/paranoid && chown fjparanoid.fjparanoid /home/paranoid

Maybe you noted we use standard /home directory for users, and maybe, like me, you don’t like it as they are mere “service” users. I agree, but sadly for how firejail works, for now, we must stick on that, as only it implement /home directory in a special way, and you should really stay in it to use it without issues.

Create utility directory for firejail:

# mkdir -p /var/lib/firejail/templates/{paranoid,secure}

If you use Devuan, debian, and probably also others, there is another limitation to take care about. Firejail doesn’t work so well with symlinks, and there are a couple of symlinks we need to get rid of. in Devuan, /dev/shm is a symlink to /run/shm. Same apply to /var/run, symlinked to /run.

A dirty but effective workaround is to put in /etc/rc.local the following lines:

rm /dev/shm
mkdir /dev/shm
mount --bind /run/shm /dev/shm
rm /var/run
mkdir /var/run
mount --bind /run /var/run

Time to configure sudo. As we launch browsers on other users from our X session, we need to add permission to our user to launch it without using a password. 

# addgroup firejail
# adduser myusername firejail
# visudo -f /etc/sudoers.d/firejail

And then in the visudo editor put this line:

%firejail ALL=(ALL) NOPASSWD: /usr/bin/firejail, /usr/bin/firetools, /usr/bin/xpra, /usr/bin/vglrun

From now on i assume you are using google-chrome-unstable, of course change it with the browser you use. 

Level 1: trusted browser

The goals for this browser session are:

  • limited access to filesystem
  • running with a dedicated user different from one i login on the machine and launch my desktop and other apps
  • access to audio, mic, webcam
  • persistent configs
  • fully usage of browser plugins and extensions
  • full access to networking

so, it offers limited protection, and it will be used only for trusted web sites. Also, it will share the same Xorg session with other apps, so, it will share resources and it cannot be considered really secure, just a little bit more than a common browser session.

edit the file /var/lib/firejail/anon-common.profile and put those line in:

whitelist ${DOWNLOADS}
mkdir ~/.config
mkdir ~/.config/google-chrome-unstable
whitelist ~/.config/google-chrome-unstable
mkdir ~/.cache
mkdir ~/.cache/google-chrome-unstable
whitelist ~/.cache/google-chrome-unstable
mkdir ~/.pki
whitelist ~/.pki
include /etc/firejail/

whitelist /dev/dri
whitelist /dev/null
whitelist /dev/full
whitelist /dev/zero
whitelist /dev/tty
whitelist /dev/pts
whitelist /dev/ptmx
whitelist /dev/random
whitelist /dev/urandom
whitelist /dev/log

blacklist /media
blacklist /mnt
blacklist /srv

those are rules applied to all of our browser sessions.

Then, create and edit /var/lib/firehail/chrome-trusted.profile and put those lines in:

noblacklist ~/.config/google-chrome-unstable
noblacklist ~/.cache/google-chrome-unstable
include /etc/firejail/
include /etc/firejail/

include /var/lib/firejail/anon-common.profile
include /etc/firejail/


whitelist /dev/nvidia0
whitelist /dev/nvidiactl
whitelist /dev/shm
whitelist /dev/snd
whitelist /dev/video0
whitelist /dev/video1
whitelist /dev/video2
whitelist /dev/video3

whitelist /var/run/pcscd/

hostname trusted
shell none

Note the line “whitelist /var/run/pcscd/”. This is needed if you have a smart card reader you want to use with chrome for certificate based authentication.

then, time to write a script to launch our browser. Create and edit /usr/local/bin/chrome-trusted and put those lines in:

xhost +SI:localuser:fjtrusted && sudo -u fjtrusted /usr/bin/firejail --name=trusted --profile=/var/lib/firejail/chrome-trusted.profile --env=DISPLAY=$DISPLAY /usr/bin/google-chrome-unstable --ssl-version-min=tls1 $@

save it, and give it execution permissions:

# chmod +x /usr/local/bin/chrome-trusted

then, you are ready to go. You now have a browser that have only limited access to filesystem ( /tmp,  /home/trusted/Download and /home/trusted/.config|.cache things in read write, other parts of the fs in read only, other parts aren’t visible at all ) and fully working with permanent configuration, running as fjtrusted user.

Note that if you launch many concurrent sessions of the chrome-trusted browser, they will end up to open a new tab on the existent browser, as it has access to the real singleton socket opened by chrome, so, they will end up in the same browser session. Take care to know it. 

Level 2: secure browser:

Goals for this level is to have a browser a little bit more secured than the trusted level, it will open different sessions if launched more time concurrently, it will NOT have persistent storage, and it can only save files in /tmp if you want to copy them in the “outside” system, if you download them in ~/Download, they will be discarded.

Also, this session will NOT have access to webcam.

It will, anyway, share the same X11 session with the rest of the system, and it will have access to the same networking as the rest. It has to be used with web sites you almost think are safe to browse, and it offer limited protection in case they aren’t.

Create and edit the file /var/lib/firejail/chrome-secure.profile and put those line in:

noblacklist ~/.config/google-chrome-unstable
noblacklist ~/.cache/google-chrome-unstable
include /etc/firejail/
include /etc/firejail/

include /var/lib/firejail/anon-common.profile
include /etc/firejail/


whitelist /dev/nvidia0
whitelist /dev/nvidiactl
whitelist /dev/shm
whitelist /dev/snd
whitelist /var/lib/firejail/templates/secure
private-template /var/lib/firejail/templates/secure
hostname secure
shell none

then create the launcher script /usr/local/bin/chrome-secure:

xhost +SI:localuser:fjsecure
sudo -u fjsecure /usr/bin/firejail --name=secure_$$ --profile=/var/lib/firejail/chrome-secure.profile /usr/bin/google-chrome-unstable --ssl-version-min=tls1 $@

and give it execution permission:

# chmod +x /usr/local/bin/chrome-secure

Now you should create your template configuration, your browser will be restored to this config every time you launch it. To do that you should launch outside the sandbox for the first time:

# sudo -u fjsecure bash
$ /usr/bin/google-chrome-unstable

and configure it how you prefer, installing your preferred extensions, and do now any configuration you really want to have. This is time also to configure eventual proxies, or adblocker and so on. Every time you would like to change any configuration in permanent manner, you will have to launch the browser this way. After the configuration is ready, close the browser and it’s time to the next trick.

As firejail will override the fjsecure user with a tmpfs, it cannot copy your “template” config from /home/secure, so, the solution is to bind mount it on another directory and make firejail copy from there.
Edit /etc/rc.local and put this line before the final exit 0:

# mount --bind /home/secure/ /var/lib/firejail/templates/secure

and you are ready.

Level 3: paranoid browser

As the name suggest, this is the more paranoid configuration. This browser will be the most volatile, anonymous  and secure browser in your system. It will not have access to any part of the fs in write mode, and even in read more it will have very limited access.

It will not access to sound, mic or cam at all. It will access network only through tor, and it will run on a separate networking namespace.

Also, it will NOT share clipboard with the X11 session, as it will run on a completely separate session using xpra.

as usual, edit the profile for this session, by creating the file /var/lib/firejail/chrome-paranoid.profile, and put those line in it:

noblacklist ~/.config/google-chrome-unstable
noblacklist ~/.cache/google-chrome-unstable
include /etc/firejail/
include /etc/firejail/

include /var/lib/firejail/anon-common.profile
include /etc/firejail/

whitelist /var/lib/firejail/templates/paranoid
private-template /var/lib/firejail/templates/paranoid

whitelist /tmp/.X11-unix/

hostname paranoid

noexec /tmp
net br1

shell none
seccomp.drop umount2,ptrace,kexec_load,kexec_file_load,open_by_handle_at,init_module,finit_module,delete_module,iopl,ioperm,swapon,swapoff,syslog,process_vm_readv,process_vm_writev,sysfs,_sysctl,adjtimex,clock_adjtime,lookup_dcookie,perf_event_open,fanotify_init,kcmp,add_key,request_key,keyctl,uselib,acct,modify_ldt,pivot_root,io_setup,io_destroy,io_getevents,io_submit,io_cancel,remap_file_pages,mbind,get_mempolicy,set_mempolicy,migrate_pages,move_pages,vmsplice,chroot,tuxcall,reboot,nfsservctl,get_kernel_syms

sometime chrome complain about not be able to sandbox it’s processes, you can both launch it with –no-sandbox ( it’s already sandboxed! ) or you can drop the line “seccomp.drop” in the profile and trust the chrome sandbox.

NOTE: this profile isn’t yet really complete, i will prepare soon a better one with also /etc override and other tricks!

now it time for the launcher: edit /usr/local/bin/chrome-paranoid:

xhost +SI:localuser:fjparanoid
export XAUTHORITY="/home/paranoid/.Xauthority"
sudo -u fjanon /usr/bin/firejail --name=paranoid_$$ --profile=/var/lib/firejail/chrome-patanoid.profile --debug --x11=xpra sh -c "/usr/bin/google-chrome-unstable --no-sandbox --ssl-version-min=tls1 $@"

then, you will have to create your configuration as done with the secure profile, so

# sudo -u fjparanoid bash
$ /usr/bin/google-chrome-unstable

here you will also have to configure a proxy for chrome to make it fully use tor. This isn’t needed to use it on normal internet web sites, but to make it resolve .onion internal address in tor, it must use a proxy.

I use privoxy, so, point it to, port 8118, type socks5

Also, you have to configure privoxy to listen on port 8118, editing the file /etc/privoxy/config and configuring:

forward-socks4a / .

And then you must configure tor too editing /etc/tor/torrc 

AutomapHostsOnResolve 1
TransPort 9040
DNSPort 53

then, add a line on /etc/modules:

# echo "dummy" >> /etc/modules

to load the dummy module at boot, and in /etc/network/interfaces add this:

auto br1
iface br1 inet static
 bridge_ports dummy0
 bridge_hello 2
 bridge_maxage 12
 bridge_stp off

and start networking

# ifup br1

last pass, fix some configs at boot by add at rc.local those lines:

mount --bind /home/paranoid/ /var/lib/firejail/templates/paranoid
# Tor's TransPort
# your internal interface
iptables -t nat -I PREROUTING -i $_int_if -p tcp --dport 8118 -j RETURN
iptables -t nat -A PREROUTING -i $_int_if -p udp --dport 53 -j REDIRECT --to-ports 53
iptables -t nat -A PREROUTING -i $_int_if -p tcp --syn -j REDIRECT --to-ports $_trans_port

save it, apply by hands all the commands in /etc/rc.local or restart your system, and the first step is ready.

What’s next?

The configurations we have done are great, and you can already start to use a more secure browser environment, but they are not enough, and many other things can be done.

In the next post, the part 3, i will talk about add cgroups to limit cpu and memory used by the browsers, i will add traffic shaping to the receipt, and than i will start talking about using apparmor to make the whole thing more secure.

Hope i will find the time to write the next part soon!

Share this story
Desktop / Laptop privacy & security of web browsers on Linux part 1: concepts and theory
Liked it? Take a second to support Nexlab on Patreon!