A big part of writing secure software (probably the biggest part) is simplicity.
When we think about software security, the first question that we ask is, “How many different ways could this program possibly be attacked?” That is, how many “ways in” are there? It’s a bit like asking “How many doors and windows are there on this building?” If your building has 1 exterior door, it’s very easy to protect that door. If it has 1000, it will be impossible to keep the building secure, no matter how good the doors are or how many security guards you have.
So we need to limit the “ways in” to our software to some reasonable number, or it won’t ever be secure. That’s accomplished by making the overall system relatively simple, or breaking it down into very simple and totally separate component parts.
Then, once we’ve limited the ways in, we need to start thinking about “How many different possible attacks are there against each way in?” We limit that by making the ways in themselves very simple. Like a door with only one unique key, instead of a door that can take five different keys, all of which individually will open the door.
Once that’s done, we limit how much damage any attack could do if it got through. For example, in a building, we’d make any given door only allow access to one room.
All of this explains, for example, why Windows is fundamentally flawed and will never be secure, and why UNIX-based systems have a better reputation for security.
Standard UNIX has a very small number of system calls that are used to implement the vast majority of all UNIX programs out there. (Even the extended list is only about 140 system calls, though most of those are never used by the average program.) Each system call is extremely specific and does one very limited thing.
Windows, on the other hand, has a ridiculous set of system calls that are confusing, take too many arguments, and do too much.
Going up to a higher level in the system, the Windows API is massive and complex. It’s a strange beast that controls both the OS and the GUI. There’s really no equivalent thing in UNIX (because the OS and the GUI are separate), but we can at least compare parts of it. Here’s The Windows Logging API. Here’s the Linux Logging API. There’s just no comparison. It’s like a joke. There’s so many “ways in” to any part of Windows that it will never be fundamentally secure.
You might say, “Well, I haven’t had a virus on my Windows machine in a long time.” That’s not what I’m talking about–I’m talking about fundamental security. In order to have a secure Windows machine, you have to have a firewall that asks you every time a program wants to make an outbound connection. You have to have a spyware scanner. You have to have antivirus software that slows down your computer by as much as 2000%. If Windows was secure, you wouldn’t need those things.
When we design our own systems, keeping them simple is the only real guarantee of security. We keep each “way in” to the system as simple as possible, and we never add more “ways in” than we absolutely need. These are compatible things, too, because the simpler each “way in” is, the fewer we’ll actually need. That may not make sense until you think about it this way: If all actions on the system can be reduced to, say, 13 fundamental function calls, then the user can do everything with those 13 calls, even if they’re not very powerful individually. If instead we only let them do 100 different specific tasks, and don’t allow them to use the 13 fundamental calls, we have to add a new function for every specific task.
There are lots of other “ways in” to a program than just its public API, too. How the user interface interacts with the backend–that involves various “ways in”. Can we access this program’s internal structure from another program? That would be another “way in.” There’s lots of ways to apply this principle.
Any way you slice it, though, the best way to get real security in things is simplicity. We shouldn’t have to put a small army in front of our software just to keep it secure. It should just fundamentally have so few “ways in” that it doesn’t need the protection, and those “ways in” should be so streamlined and simple that they’re impossible to exploit.