Software Security Anti-Patterns
by Eric Boersma
If you’re like a lot of developers, you might not think much about software security. Sure, you hash your users’ passwords before they’re stored in your database. You don’t return sensitive information in error messages. Each time you log something, you make sure it removes sensitive data. But beyond that, you don’t spend much time thinking about the security of your app.
Chances are, you and your team think that’s OK. After all, nobody’s compromised your application yet. Thinking about security is hard, and nobody on your management team is pressuring you to make your app more secure. They definitely are pressuring you to ship that next feature tomorrow, though.
My goal here isn’t to make you feel guilty about your application security practices. But it is to raise some awareness of things in your application that you might be missing. Many teams make similar mistakes when it comes to software security. They make those mistakes because they’re easy to make, and doing things the right way is usually hard or more expensive. I call these habits “anti-patterns” because they’re common practices of software teams that actually harm the teams that adopt them.
The goal of this article is to dive into some of the most common security anti-patterns teams fall into and just why they can be harmful.
Using Libraries Without Knowing Everything They Do
This is probably the single most common security anti-pattern teams fall into. I’m guilty of it myself sometimes if we’re being honest. Modern software relies on dozens of open source libraries written by developers outside of your team. The truth is that most developers don’t know what all of the libraries in their project actually do.
Not knowing what all of the libraries in your application do is a very dangerous position to be in. Consider the tale of the “leftpad” NPM package, which in 2016 broke the Node Package Management (NPM) repository. Removing this one package broke builds for thousands of NPM packages and, subsequently, the applications of thousands of businesses. Why did that happen? Because the guy who built leftpad was upset at the NPM admins. Most of the people who relied on packages that relied on leftpad had no idea it was a package that they were using. What’s more embarrassing is that all leftpad does is add some white space to the left side of a provided string. It’s embarrassingly simple.
If the author of leftpad had been actively malicious instead of simply pulling his library from NPM, thousands of developers could have had their application details secretly stolen by updates to leftpad. They never would’ve known because they didn’t know they were using the library in the first place. They’d never done an audit of the libraries their package uses. Even avoiding malicious users, many NPM packages contain known security vulnerabilities in the code. Node even provides a method for scanning them. Yet many teams have never run that scanner even a single time.
Using Production Data on Test Servers
This is another of the most common security anti-patterns. Let’s be honest: it’s difficult to come up with good test data. There are only so many cartoon characters you can name fake users after. Inventing fake addresses becomes pretty difficult after a while. Generating convincing fake medical data can be nearly impossible for someone who doesn’t understand the intricacies of what they’re dealing with.
So, many teams just use their production data right on the test system. This carries a whole bunch of potential problems along with it.
For starters, most production data contains sensitive information along with it. Your users trust your company enough to share things like addresses or phone numbers. If you work in certain environments, they might share even more sensitive information, like their banking or government ID numbers, or even medical histories. They share that information because they trust that unauthorized people won’t access that data. When you move production data to a test system, you run the risk of breaking that trust.
Most test environments aren’t nearly as secure as your production environments. It’s common to share administrator logins for test systems, while you wouldn’t ever do that for production systems. This means that unauthorized people—like junior associates, or contractors—can access that data. In many countries, this data may even be legally protected, and using it in a test environment might be breaking the law.
Thankfully, great tools exist that can help deal with this problem. Top-tier test environment management platforms and data compliance platforms make it easy to manage the data used in your test environments, which keeps production data safe.
Using Blacklists for Input Validation
To be honest, a lot of software would be simpler without users. Unfortunately, it’d be a lot less useful too. So you need to accept input from your users, but you need to make sure they’re not sending you anything bad. So this means nothing malicious, or nothing that might accidentally break something. In short, you start validating user input.
This is a good thing. Validating user input helps your software stay safe and stable. But a really common error teams make is trying to rule out inputs specifically. They create a list of rules that data can’t match, or it’s rejected. Everything else is accepted. This is a good first step, but it has some pretty serious holes, making it another security anti-pattern. Specifically, “everything” is a pretty wide data set.
These kinds of rules tend to be reactionary, where teams will add to them when a new bug or security flaw is found. This means that you’re protected against every flaw you know about, but there’s a whole universe of threats you don’t know about.
Instead, teams should focus on creating a white list of acceptable inputs, and only allowing those. This means that your surface area for bugs and attacks is much smaller.
Carelessly Concatenating Strings
This is the sort of thing that a lot of developers think they don’t need to worry about anymore. Sure, worrying about string concatenation in C was a big deal, but their attitude is that it’s totally safe these days.
Unfortunately, there are lots of situations where that’s just not true, making it another security anti-pattern. As it turns out, it’s really difficult to effectively separate input from code, especially when pushing strings together. This means that carelessly input data can crash your servers or expose security flaws.
An example of this happening in a language that many believed to be secure was 2013’s YAML deserialization vulnerability in Ruby. It was possible for a YAML file, which was just supposed to hold configuration, to instead be evaluated as code. This code could contain bugs or security flaws. YAML was the sort of thing used everywhere in Ruby, and still is (the vulnerability has been patched). Developers were carelessly injecting security vulnerabilities into their apps without having a sense of the danger present.
Is Your Team Falling Into Bad Habits?
This article doesn’t hold every security anti-pattern in the book. These are just the ones that I’ve run into the most frequently. They happen because teams cut corners with the way they handle data or think about their inputs. Every team receives pressure from management to improve time to release, which means simple things slip through the cracks. It isn’t until months or years later that someone discovers the flaws present in the code.
The best way to catch these anti-patterns is to be vigilant while you’re working. The best engineers can recognize their teams slipping into these anti-patterns and ensure that they’re addressed before they become an issue. If your team is struggling with these kinds of problems, now is the time to address them. You can make your team’s code more secure, but it requires that you put in the time now. What bad habits can you stop your team from carrying on?
This post was written by Eric Boersma. Eric is a software developer and development manager who’s done everything from IT security in pharmaceuticals to writing intelligence software for the US government to building international development teams for non-profits. He loves to talk about the things he’s learned along the way, and he enjoys listening to and learning from others as well.
We often get asked by people “What is TEM (Test Environment Management), well for those of you looking for a quick overview of Test Environment Management, here is Use Case we developed as a way…
19 MARCH, 2020 by Michiel Mulders SRE vs DevOps: Friends or Foes? Nowadays, there’s a lack of clarity about the difference between site reliability engineering (SRE) and development and operations (DevOps). There’s definitely an overlap between the roles, even though...
06 MARCH, 2020 by Arnab Roy Chowdhury Top 10 SRE Practices Do you know what the key to a successful website is? Well, you’re probably going to say that it’s quality coding. However, today, there’s one more aspect that we should consider. That’s reliability. There are...
20 FEBRUARY, 2020 by Arnab Row Chowdhury Technically, the world today has advanced to a level we never could’ve imagined a few years ago. What do you think made it possible? We now understand complexities. And how do you think that became possible? Literacy! Since...
14 FEBRUARY, 2020 by Michiel Mulders A site reliability engineer loves optimizing inefficient processes but also needs coding skills. He or she must have a deep understanding of the software to optimize processes. Therefore, we can say an SRE contributes directly to...
07 February, 2020 by Arnab Roy Chowdhury Do you remember what Uncle Ben said to young Peter Parker? “With great power comes great responsibility.” The same applies to companies. At present, businesses hold a huge amount of data—not only the data of a company but also...