Title: OpenBSD workstation hardening | |
Author: Solène | |
Date: 31 December 2023 | |
Tags: security openbsd unix | |
Description: In this blog post, you will learn different methods to | |
harden your OpenBSD system, and in which situation they are useful | |
# Introduction | |
I wanted to share a list of hardening you can do on your OpenBSD | |
workstation, and explaining the threat model of each change. | |
OpenBSD official project website | |
Feel free to pick any tweak you find useful for your use-case, many are | |
certainly overkill for most people, but depending on the context, these | |
changes could make sense for others. | |
# User configuration | |
There are some tweaks that could be done in the configuration of a user | |
to improve the security. | |
## The Least privileges | |
In order to prevent a program to escalate privileges, remove yourself | |
from the wheel group, and don't set any doas or sudo permission. | |
If you need root privileges, switch to a TTY using the root user. | |
## Multiple-factor authentication | |
In some cases, it may be desirable to have a multiple factor | |
authentication, this mean that in order to log in your system, you | |
would need a TOTP generator (phone app typically, or a password manager | |
such as KeePassXC) in addition to your regular password. | |
This would protect against people nearby who may be able to guess your | |
system password. | |
I already wrote a guide explaining how to add TOTP to an OpenBSD login. | |
Blog post: Multi-factor authentication on OpenBSD | |
## Home directory permission | |
The permissions of the user directory should be 700, so only the owner | |
and root could browse it. | |
Ideally, you should add `umask 077` to your user environment, so every | |
new directory or file permissions will be restricted to your user only. | |
# Firewall | |
There are some interesting policies to configure with the help of | |
OpenBSD firewall Packet Filter. | |
## Block inbound | |
By default, it's good practice to disable all incoming traffic except | |
the responses to established sessions (so servers can reply to your | |
requests). This protects against someone on your local network / VPN | |
to access network services that would be listening on the network | |
interfaces. | |
In `/etc/pf.conf` you would have to replace the default: | |
``` | |
block return | |
pass | |
``` | |
By the following: | |
``` | |
block all | |
pass out inet | |
# allow ICMP because it's useful | |
pass in proto icmp | |
``` | |
Then, reload with `pfctl -f /etc/pf.conf`, if you ever need to allow a | |
port on the network, add the according rule in the file. | |
## Filter outbound | |
It may be useful and effective to block outbound traffic, but this only | |
work effectively if you know exactly what you need because you will | |
have to allow hosts and remote ports manually. | |
It would protect against a program trying to exfiltrate data using a | |
non-allowed port/host. | |
# Disabling network for the desktop user | |
Disabling network by default is an important mitigation in my opinion. | |
This will protect against any program your run and try to act rogue, if | |
they can't figure there is a proxy, they won't be able to connect to | |
the Internet. | |
This could also save you from mistaken commands that would pull stuff | |
from the network like pip, npm and co. I think it's always great to | |
have a tight control on which program should do networking and which | |
shouldn't. On Linux this is actually easy to do, but on OpenBSD we | |
can't restrict a single program so a proxy is the only solution. | |
This can be done by creating a new user named `_proxy` (or whatever the | |
name you prefer) using `useradd -s /sbin/nologin -m _proxy` and adding | |
your SSH key to its authorized_keys file. | |
Add this rule at the end of your file `/etc/pf.conf` and then reload | |
with `pfctl -f /etc/pf.conf`: | |
``` | |
block return out proto {tcp udp} user solene | |
``` | |
Now, if you want to allow a program to use the network, you need to: | |
* toggle the proxy ON with the command: `ssh -N -D 10000 | |
_proxy@localhost` which is only possible if your SSH private key is | |
unlocked | |
* configure a SOCKS5 proxy in the program | |
### Some network fixes | |
Most programs will react to a proxy configured in a variable named | |
`http_proxy` or `https_proxy` or `all_proxy`, however it's not a good | |
idea to globally define these variables for your user as it would be a | |
lot easier to a program to use the proxy automatically, which is | |
against the essence of this proxy. | |
#### SSH | |
By default, you won't be able to ssh to anything except on a local | |
user, we need to proxy every remote ssh connection through the local | |
_proxy user. | |
In `~/.ssh/config`: | |
``` | |
Host localhost | |
User _proxy | |
ControlMaster auto | |
ControlPath ~/.ssh/%h%p%r.sock | |
ControlPersist 60 | |
Host *.* | |
ProxyJump localhost | |
``` | |
#### Chromium | |
If you didn't configure GNOME proxy settings, Chromium / Ungoogled | |
Chromium won't use a proxy, except if you add a command line parameter | |
`--proxy-server=socks5://localhost:10000`. | |
I tried to manually modified the dconf database where the "GNOME" | |
settings are to configure the proxy, but I didn't get it to work (it | |
used to work for me, but I can't succeed anymore). | |
#### Syncthing | |
If you use syncthing, you need to proxy all its traffic through the SSH | |
tunnel. This is done by setting the environment variable | |
`all_proxy=socks5://localhost:10000` in the program environment. | |
# Live in a temporary file-system | |
It's possible to have most of your home directory be a temporary file | |
system living in memory, with a few directories with persistency. | |
This change would prevent anyone from using temporary files or cache | |
left-over from previous session. | |
The most efficient method to achieve this is to use the program | |
home-impermanence that I wrote for this use case, it handles a list of | |
files/directories that should be persistent. | |
Blog post: Reproducible clean $HOME on OpenBSD using impermanence | |
If you only want to start fresh using a template (that doesn't evolve | |
on use), you can check the flag `-P` of `mount_mfs` which allows | |
populating the fresh memory based file system using an existing | |
directory. | |
OpenBSD man page: mount_mfs(8) | |
# Disable webcam and microphone | |
Good news! I take the opportunity here to remember OpenBSD disables by | |
default the video and audio recording of the various capable devices, | |
instead, they will appear to work but record empty stream of data. | |
They can be manually enabled by changing the sysctls | |
`kern.audio.record` or `kern.video.record` to 1 when you need to use | |
them. | |
Some laptop manufacturer offer the option to have a physical switch to | |
disable microphone and webcam, so you can be confident about their | |
state (Framework). Some other manufacturer also allow to not put any | |
webcam and microphone (NovaCustom, Nitropad). Finally, open source | |
firmwares like Coreboot can offer a bios setting to disable these | |
peripherals, it should be trustable in my opinion. | |
# Disabling USB ports | |
If you need to protect your system from malicious USB devices (usually | |
in an office environment), you should disable them in the BIOS/Firmware | |
if possible. | |
If it's not possible, then you could still disable the kernel drivers | |
at boot time using this method. | |
Create the file `/etc/bsd.re-config` and add the content to it: | |
``` | |
disable usb | |
disable xhci | |
``` | |
This will disable the support for USB 3 and 2 controllers. On a | |
desktop computer, you may want to use PS/2 peripherals in these | |
conditions. | |
# System-wide services | |
## Clamav antivirus | |
While this one may make you smile, if there is a chance it saves you | |
once, I think it's still a valuable addition to any kind of hardening. | |
A downloaded attachment from an email, or rogue JPG file could still | |
harm your system. | |
OpenBSD ships a fully working clamav service, don't forget to enable | |
freshclam, the viral database updater. | |
## Auto-update | |
I already covered it in a previous article about anacron, but in my | |
opinion, auto-updating the packages and base system daily on a computer | |
is the minimum that should be done everywhere. | |
Anacron: useful OpenBSD examples | |
# System configuration | |
## Memory allocation hardening | |
The OpenBSD malloc system allows you to enable some extra checks, like | |
use after free, heap overflow or guard pages, they can be all enabled | |
at once. This is really efficient for security as most security | |
exploits relies on memory management issues, BUT it may break software | |
that have memory management issues (there are many of them). Using | |
this mode will also impact the performance negatively, as the system | |
needs to do more checks for each piece of allocated memory. | |
In order to enable it, add this to `/etc/sysctl.conf`: | |
``` | |
vm.malloc_conf=S | |
``` | |
It can be immediately enabled with `sysctl vm.malloc_conf=S`, and | |
disabled by setting no value `sysctl vm.malloc_conf=""`. | |
The program `ssh` and `sshd` always run with this flag enabled, even if | |
it's disabled system-wide. | |
# Some ideas to go further | |
## Specialized proxies | |
It could be possible to have different proxy users, with each | |
restriction to the remote ports allowed, we could imagine proxies like: | |
* http / https / ftp | |
* ssh only | |
* imap / smtp | |
* etc.... | |
Of course, this is even more tedious than the multipurpose proxy, but | |
at least, it's harder for a program to guess what proxy to use, | |
especially if you don't connect them all at once. | |
## Run process using dedicated users | |
I wrote a bit about this in the past, for command line programs, | |
running them in dedicated local users over SSH make sense, as long as | |
it's still practical. | |
Dedicated users to run processes | |
But if you need to run graphical programs, this becomes tricky. Using | |
`ssh -Y` gives the remote program a full access to your display server, | |
which has access to everything else running, not great... You could | |
still rely on `ssh -X` which enables X11 Security extensions, but you | |
have to trust the implementation, and it comes with issues like no | |
shared clipboard, poor performance and programs crashing when | |
attempting to access a legit resource that is blocked by the security | |
protocol... | |
In my opinion, the best way to achieve isolation for graphical programs | |
would be to run a dedicated VNC server in the local user, and connect | |
from your own user. This should be better than running on your own X | |
locally. | |
## Encrypted home with USB unlocking | |
In a setup where the computer is used by multiple person, the system | |
encryption may be tedious because everyone have to remember the main | |
passphrase, you have no guarantee one won't write it down on a | |
post-it... In that case, it may be better to have a personal volume, | |
encrypted, for each user. | |
I don't have an implementation yet, but I got a nice idea. Adding a | |
volume for a user would look like the following: | |
* take a dedicated USB memory stick for this user, this will be used as | |
a "key" to unlock their data directory | |
* overwrite the memory stick with random data | |
* create an empty disk file on the system, it will contain the | |
encrypted virtual disk, use a random part of the USB disk for the | |
passphrase (you will have to write down the length + offset) | |
* write a rc file that looks for the USB disk volume if present, if so, | |
tries to unlock and mount the partition upon boot | |
This way, you only need to have your USB memory stick plugged in when | |
the system is booting, and it should automatically unlock and mount | |
your personal encrypted volume. Note that if you want to switch user, | |
you would have to reboot to unlock their drive if you don't want to | |
mess with the command line. | |
# Conclusion | |
It's always possible to harden a system more and more, but the balance | |
between real world security and actual usability should always be | |
studied. | |
No one will use a too-much hardened system if they can't work on it | |
efficiently, on the other hand, users expect their system to protect | |
them against most common threats. | |
Depending on one's environment and threat model, it's important to | |
configure their system accordingly. |