Secure code is essential. Data breaches happen for many reasons, poor coding among them because poor coding practices make it too easy. When your software is not designed with security in mind, a teenager can download a tool from the internet, point it at your site, and steal your data.
Secure coding practices can range from high-level principles to detailed code analysis. Each programming language has its own nuances and techniques to securely coding within its environment. A discussion of secure coding for every popular language would be a massive tome.
Instead of listing coding samples ad nauseam, we trust you as a developer to know the language and framework you use. We’ll discuss the secure coding practices you actually need to know that apply to any language or framework. These are the principles used to secure software. Apply these principles for securing software to your distinct environment.
The OWASP Top 10 2017 lists the most common and dangerous web application vulnerabilities. Four out of the ten vulnerabilities in the list are dangerous examples of trusting the user too much.
We’re not advocating an antagonistic attitude toward end users. But it’s important to realize what end users of the application have the power to do. Most users want to accomplish a task with your application. Some will want to see if they can break it. Fewer will find a way to break it for their own gain.
Four vulnerabilities come from trusting the user too much: Injection, XML External Entities, Cross-site Scripting (XSS), and Insecure Deserialization. All have one thing in common: the application trusts what the user gives it, often leading to executing data as code. In the worst case, the application will execute whatever code the attacker wants to execute (such as opening a bash shell or downloading and installing malware).
The principle of least trust offers a solution. Any data that enters your application has to be validated before it is used. Act like border patrol–inspect any data trying to come into your application, determine if it’s safe, then let it in. If it’s unsafe or you can’t tell, reject it (nicely, in case of an actual error on the part of a legitimate user).
Many tools used by unsophisticated attackers depend on vulnerabilities like injection and XSS to gain easy access. Don’t be an easy target for the 12-year-old down the street.
Simple is easier to secure. Keep your designs simple, and you can prove the security of a system.
Unfortunately, some developers overthink the design (it happens to everyone at some point) and add too many hoops, bells, and whistles. Over time, an application may grow and become a complex behemoth that is hard to understand and even harder to secure. Try your best not to let this happen.
Think of your software in terms of the business outcome it enables. Software isn’t a place to create works of art or to impress your friends with how clever you can be. One visit to The Daily WTF will show you how strange software architecture can get.
When your software design is focused on the business outcome, you’ll naturally gravitate toward the simplest way to achieve the outcome. When all pieces of the application are clearly understood, they can be reviewed for coding security flaws and made safe.
Unfortunately, security has been viewed as an impediment to getting things done instead of an enabler. That mindset has to change on both sides.
An effective way to incorporate security into your code is through automation. Automation reduces the chance of human error. It puts important processes on autopilot and can eliminate dangerous variables.
As software moves to the cloud, the servers running the software are often built on demand. If someone has to create new servers every time one is needed, the chance of mistakes creeping in rises. Automation can be built to create servers with the same blueprint every time, making sure all code security practices are followed consistently.
Without security automation, true security at scale cannot happen. Automation helps to include security early and often in the software development process and enables fast feedback.
Margo Cronin, Cloud Solution Architect at AWS, outlined four ways to get started in security automation at the European DevOps Enterprise Summit:
Establish your level of trust
Security by design
Securing the pipeline
Modern development practices encourage automation wherever possible. Security is no different.
Threat modeling is the practice of examining a software design to find places where attackers could compromise it. Threat modeling helps developers to understand how attackers could compromise their software so they can build in the appropriate defenses.
The first step to building secure software is not learning new syntax or coding techniques. You need to understand how attackers break into software systems. Walk through a compromise to see how easy a data breach could happen if you write code or design the application in the wrong way.
If you’ve never threat modeled an application before, here are the basic steps:
Document how the application functions, focusing on the flow of data through the application.
Find threats against the application by following the flow of data and identifying places weak to certain exploits (attack databases work well here).
Address threats by rating them and deciding on mitigation strategies.
Validate the model to make sure you didn’t miss anything.
Threat modeling is an ongoing activity. When changes are made to the application architecture, threat model again to make sure the new pieces aren’t introducing new threats.
Threat modeling done right automatically makes your code more secure, You’ll build security in, instead of bolting it on at the end of development.
Data is the lifeblood of the business and the life of your users. A massive data breach can take years, and millions of dollars, to recover from. Good cryptographic processes help to mitigate the damage if the worst happens.
When done incorrectly, cryptography is a waste. Making common cryptographic mistakes leads to disaster when good attackers figure out what you’re doing. Here are some do’s and don’ts for cryptography:
DON’T store cryptographic keys in the same place as the data it encrypts.
DON’T hard code cryptographic keys in the code.
DON’T create your own cryptographic algorithms or use broken algorithms.
DO use known good algorithms provided by your framework (AES-256, Argon2, PBKDF2).
DO encrypt data at rest and in transit.
DO have a security expert review any code using cryptography.
Take the time to learn the common mistakes and you’ll keep them from popping up in your code.
By reading this far, you’ve proven that you’re interested in security. That’s awesome! The development community can never have too many developers who know security and write secure code.
Applications are ultimately built by developers. Without developers who care about secure code, we have no hope of writing better software.
Take pride in coding securely. Treat security like any other measure of code quality. Start by choosing one principle to apply to your code. Find areas within your current projects where you can make your code just a little safer.
When everyone’s code is a little safer, the world is a little safer.