May 21, 2013, 4:56 PM — In the 10 years since I launched my consulting/training venture, I've worked with thousands of software developers around the world. As you might expect, I've seen many software security failures. Given that experience, I'm often asked what I think are the biggest, baddest mistakes made in software today.
In response, I don't cite specific failures. That's what the OWASP Top-10 does. It and similar lists serve a purpose, but at heart they describe a set of symptoms of just a few, far bigger problems.
The two biggest problems I see -- focusing too much on functional specifications, and being overly trusting -- are in a sense two sides of the same coin. And it seems to me that pretty much the entire OWASP Top-10 list stems from these two things.
It's easy to understand why these problems are so persistent. The vast majority of software developers I've met and worked with are highly intelligent, motivated people. They often work in extremely stressful environments, with seemingly impossible deadlines to meet and a management team that seems to be uncompromising on those deadlines. With those pressures, it's not at all surprising that developers tend to focus most on the functionality of their products at the expense of other considerations, such as security. "What features does the customer need?" seems a more pressing question than "What can go wrong?" or "How can an attacker trick the software into misbehaving?"
The other side of the coin is a general underestimation of threats. That, of course, makes it easier for developers to shift their focus overwhelmingly to the functionality side of things. The problem here is that developers tend to be overly trusting in everything from users to the APIs they use in their code.
When you focus only on building functionality and not preventing unspecified functionality, you don't anticipate potential attacks, and you end up with the OWASP Top-10 and other lists like it.
This is my message: Building functionality is indispensable, but so is preventing code from doing things you don't anticipate. Getting that right is the tough part, of course.
I've found two things that are enormously helpful in getting it right. The first is to take an active role in marshaling data through an application. That starts with rigorously validating inputs, and it ends with ensuring that data output cannot cause any harm in its intended environment. The second is to anticipate and handle exception conditions properly.