All else being equal, the simpler solution is the most secure. Chad Perrin explains the tactics that can be employed to simplify systems.
All else being equal, the simpler solution is the most secure.
The more code we write for a given software system, the more opportunity there is for bugs to creep into the code. That opportunity for more bugs results, statistically, in a simple relationship between source lines of code and bug counts: more code, more bugs. Because many (if not all) bugs can be exploited as security vulnerabilities, the amount of code in a single software system can have a significant impact on the security of the system.
Adding features to a software system, regardless of the number of lines of code needed to implement those features, can also increase the opportunity for bugs to arise. This is because the interactions of different pieces of functionality in the system can sometimes have surprising effects, particularly when those features are heavily dependent upon each other. Such danger increases as the features become increasingly parallelized, because multiple features can be dependent upon the behavior of a single feature at the same time — and can also influence the behavior of that single feature simultaneously, thus having unplanned influence on each other through that common dependency.
In addition to the strictly technical security consequences of complexity, there is also the problem of our ability to understand complex systems. The greater a system's complexity, the more difficult it is for a single individual to understand all the ways different parts of the system might interact with each other. When such interactions between the parts of a system are not fully understood, the people whose job it is to maintain the system will not be cognizant of the security implications of those interactions, and will thus be unable to properly address such issues.
Simplification, then, is an important security strategy. There are a number of different tactics that can be employed to help simplify systems:
- Minimal Design: Resisting the urge to add features to a system can be difficult, but the rewards of such resistance can be measured in frustration and difficulty avoided. When considering whether to add additional capabilities to a system, consider whether they are actually needed or merely wish-list items that may never be truly useful.
- Modularity: In cases where a single system might have a multitude of uses, and those uses may involve local implementation of the system, the ability to pick and choose which parts of the system to include in a local implementation can help keep that specific use of the system as simplified as possible. For this reason, breaking the system into "modules" that can be included or excluded as needed helps serve the needs of more users without as much of an increase in complexity in practice as one could expect from just including every possible piece of functionality in a single whole system such that they cannot be left out when they are not needed.
- Separation of Concerns: Separating functionality into discrete parts that do not directly interact can help minimize the complexity of the system. This is often known as "separation of concerns". By increasing the independence of parts of a system, dealing with the management of each part becomes easier without accidentally exposing the system to unexpected security issues.
An essential statement of what is often called the Unix philosophy is "do one thing well". The idea is that each tool in the system should ideally be designed to do only one thing, and to do it well. When more than one thing at a time needs to be done, multiple tools can be used together to achieve the needed complexity, so that such complexity does not become a permanent part of the system itself. The design of Unix and Unix-like systems offers simple mechanisms for automation and creating ad-hoc, temporary connections between discrete tools, so that a policy of making single-purpose tools that can be flexibly made to work with other tools to accomplish more complex tasks is well supported and encouraged.
It may not be a silver bullet for security, but such an approach to keeping the system simple covers all three of the above bullet points for simplifying systems: minimal design, modularity, and separation of concerns. As such, the security benefits of the Unix philosophy, which exhorts us to make software tools that "do one thing well", should not be ignored.