It’s hard to write a single definitive article for writing secure code, because languages differ so broadly and they all have different vulnerabilities and we’d be here for years trying to get them all: preventing a memory leak in C is a totally different ballgame from preventing DOM-based XSS attacks in the JavaScript. Still, there are principles that can be adhered to across languages that will help you and your team to be more secure, and today we’re breaking them down.
Cover Your Basics
The 2017 Equifax breach is one of the single largest breaches in history. It leaked the personal information of 147 million people, and cost the company $700 million dollars. It happened—at least in part—because the admin password was ‘admin’. You’d be amazed at how many major breaches happen for, well, stupid reasons where somebody should’ve known better.
Surely we didn’t give the public website search engine the ability to index our staging server (hi, the New Zealand Treasury Department!); surely the IT guy isn’t connecting to the public Wi-Fi network from the street outside; surely nobody is storing the root password in a plaintext file on their desktop called passwords.
If you ever find yourself saying “surely they did x, x is about as basic as things get” and there’s even a shred of doubt, check. Being thorough about the small and boring things is one of the simplest and most effective ways to keep your systems locked down.
Implement Access Control
Social engineering has been one of the primary attack vectors since, well … since two people got together and one of them decided to trick the other. At least one InfoSec commentator has said the first social engineering attack was in the Garden of Eden, where the snake tricked superuser Eve into opening AppleOfKnowledge.exe and accidentally copying the whole database right into her brainpan. The admin was not, to put a fine point on it, happy. The point is that every system—no matter how well-built—has the same weakness: at some point, there’s a human in the system, and that human can be tricked.
Reducing the number of people with access to passwords or other secure information significantly reduces the chances that one of them is going to be the weak point. This can be a right pain: it slows down work, and there’s always the temptation to share access more broadly to keep the wheels from squeaking.
You can do that, but the more you do it, the greater your risk of a malicious actor getting in. You need to balance your security needs against your need to, you know … do business. Perfect access control would be nobody having the passwords, and the password only gives you access to a brick. Which leads to our next point:
Operational Security
We’ve already ascertained that humans are the weak point in most systems and that it’s almost impossible to exclude them entirely without just shutting down your business, so what can you do?
You can brief your less-technical staff on good security practice. Simple things like using a password manager, like making sure unexpected visitors wait in the lobby while you check their credentials, like not plugging in USBs that don’t come from totally trusted (and properly-secured) sources.
Look at your business from the outside, as if you were a hacker, and ask how would I break in? then make sure you locked them down and educate your staff on how to mitigate those risks. If you’re running a larger business you probably want to set up a SOC, but for smaller businesses this often means just covering your bases and making sure all your staff are briefed on best practice.
Log Everything
There’s two parts to this:
- Log things
- Actually read your logs
Most folks are fine with #1, but #2 is where too many IT teams trip up. Logs give you critical insight into how your systems are being used—they can help you detect intrusion, but checking them is also just generally good for the health of your code. Think of it like going to the dentist: sure it’s a little painful, but if you only go when your teeth are falling out it’s going to be a lot worse.
Comment On Your Code
Hey, developers! How often does this happen: you’re refactoring some old code and you come across something … weird. You don’t know what it does, but it works fine and taking it out seems to break things, so you just paint over it and leave it alone.
We’ve all done it: nobody wants to spend six weeks figuring out the bizarre magic some programmer did in PERL in 1994 in order to change absolutely nothing about how the program runs. If it ain’t broke, don’t fix it, we all say.
Except it is broken. Just because it’s not visible doesn’t mean everything is fine. If something goes wrong around that piece of PERL—there’s a vulnerability or even just a bug—the whole house of cards comes crashing down.
Now, we’re not time-travellers and we can’t go back to 1994 and pick that programmer’s brain (or even call their new workplace: that might be kinda weird), but what we can do is write clear code and documentation going forward. It’s good practice for code generally, but it’s also critically important in security—we can’t protect or fix systems that we don’t understand.
Back Up Everything
When NotPetya ripped through Northern Europe, it almost tore the Maersk company to pieces. You know what saved them? One single staff member in an Australian office who’d made a backup, and stores it on a drive not connected to the internet. 20% of global shipping was in total lockdown, and a single backup got it moving again. Back ups aren’t useful until after everything has gone wrong but, after a disaster, they’re an absolute lifesaver. You ideally want regular auto-backups with a semi-regular manual backup.
Install Those Updates
Nobody likes installing updates; they feel like a waste of time, they rarely look like they’re doing anything, or they add shiney new features we never asked for. They’re also one of the easiest ways to keep everything secure, and failure to update is responsible for, well … Equifax, for one. Part of it was that some of their admin passwords were ‘admin’, but a major part of it was that they had unpatched servers. If there’s a 0day we know about, it’s probably covered in a patch somewhere. If you don’t install that patch, you’re leaving your vault door wide open.
Okay so, what do I do?
The boring stuff. The little stuff. The stuff that’s annoying, and makes you go “maaaaybe if I skip it, nobody will notice.” Not to diminish the role of incident response (incident response teams are angels—better to have them and not need them, you know?), but if you take maintenance and security seriously, you can save everybody, including incident response, a lot of headaches. Best practice is actually following best practice. Implement better OpSec, sort out access control, finally install that SSL certificate. Generally keep your ear to the ground: read up on cybersecurity tips, known vulnerabilities, and infosec news. The first stage in good defence is awareness, the second is preparation; actual defence is pretty far down the ladder, because if you’re at that stage, something else has gone wrong.