Thoughts on software security

Created at 2024-04-15

Modern software is a house of cards. The Linux kernel itself contains over 100,000 lines of code, drivers amount to approximately 7 million lines of code. The node.js package ecosystem is known for its hard-to-control package supply chain. There is so much code, and so many authors, we trust blindly every day. Much attack surface is even unnecessary, such as an obscure REST endpoint of your probably unpatched Nextcloud or Wordpress instance. If I think about it, working with my computer is like hanging on a chain, the links of which are handmade by thousands different people.

Many authors are very cautious, but still, security vulnerabilities happen (should I mention recent incidents?). In the past, our security-critical software had dangerous vulnerabilities that were only found months later. If nothing has changed, the software we use *right now* has dangerous vulnerabilities we don't know about, too, and resourceful actors will occasionally exploit some of them before the white hats find them. Indeed, according to the zero-day tracking project, every year since 2006, there have been over 20 zero-day vulnarabilities, i.e. vulnerabilities actively exploited before a patch was available. Of course, not *all* of them are equally dangerous, but some are. Moreover, these are only the *known* zero-days, the ones we noticed; we can't be sure these are all.

Hence, I find it really hard to feel confident in the security of our software systems.

So what should we do about it beyond regularly patching our software? I don't know, as I'm not a security engineer. In this article, I just want to present a few concepts I personally find relevant for my treatment of software security, in particular regarding hosting software on a server and managing the security of my online accounts.

With great privilege comes great responsibility

When we hear of privilege escalation vulnerabilities, we think of kernel bugs that allow an unprivileged process to gain root privileges, but the problem is much more general.

For example, let us assume we write a script `tool.sh` (owned by the current user paulpaul), make it executable and later run it with `sudo`. We have created an opportunity for privilege escalation: A malicious actor that managed to execute code as paulpaul can easily append a malicious command to `tool.sh`, and the next time we run `sudo tool.sh`, the command is executed with elevated privileges!

I propose to summarize this situation in the following commandment: *When a user is allowed to modify an executable, users with higher privileges should not execute that file.*

As a more general rule: *The more rights the unprivileged users have, the more cautious the privileged ones need to be.*

The Bell-LaPadula model is concerned with the flow of information and is another example of this rule. It is designed to avoid the leaking of confidential information. The slogan is "write up, read down": Users and resources are assigned confidentiality levels. Information must not flow down: A user can read all the resources below themselves, as this constitutes an upward flow of information. Therefore, the more privileged a user is, the more they can read; this is the idea of a security clearance. What's more surprising is that in the Bell-LaPadula model, users are not allowed to write resources below them, as this would constitute a downward flow of information. Hence, the more privileged a user is, the *less* they can write! This is quite a draconian measure, as a careful user might make sure not to leak their confidential knowledge, and even secret service officials violate it when they give interviews to the press. (One might say, humanity has gained fire through a Protean security breach of the Gods' Bell-LaPadula multi-level security policy, where information may only flow upwards the Olympus. This could also explain why the Gods rarely present themselves to humans.)

Granting more permissions to less privileged users may improve security

Effective security is not about taking privileges away from non-root users, it is about *having a distribution of privileges that allows each user to do their job with as few rights as possible*. Otherwise, the less privileged users will be of no use and everyone will use `sudo` all the time. I think we need to think a lot more about fine-grained permissions, for example:

Create extremely simple protocols and software

I have a self-hosted Nextcloud instance, but I only use it to manage and synchronize my calendar. Once I decided to get rid of it, implementing my own minimalistic CalDAV server. Naïvely, I imagined I'd write a simple backend that

Reading the RFCs, here is what I learned:

I finally ditched the project because it was too much of a time investment for a small hobby project to even implement the bare minimum. The complex query language feels over-engineered for my use case (synchronization).

I really wish our protocols were dead-simple:

(Interestingly, XML was designed to be simple, and maybe it is really simpler than older formats. Or it is as simple as it gets if you want to achieve the high extensibility of XML. Either way, XML is complex enough to offer lots of security pitfalls)).

Why are our de-facto-protocols so complicated? For lower-level protocols, think HTTP, the reason is most probably performance: Many complications, such as "Connection: keep-alive" and caching, exist for precisely this reason.

From theory to practice

I recently thought a lot about security, for one, because I am in a process of moving my web services to a Virtual Private Server, which means more responsibility for me. In the process, I thought about security risks. I decided to use a static site generator for this blog instead of the Wordpress page I once had, but I have not yet gotten rid of Nextcloud (because of the calendar), which is also a one-size-fits-all piece of software you need to carefully configure and patch. So for now it's running behind HTTP basic authentication, in which I trust more than Nextcloud due to its inherent simplicity.

SELinux allowed me to implement some of the privilege-related ideas. I like that it is so fine-grained, and I find this a much more convincing benefit than the fact that it realizes Mandatory Access Control.

Either way, security is a process, not a product, so there's still room for improvement. Only hosting the things I'm confident of feels a bit ascetic, but that's where I am right now.