Every few years, the Open Web Application Security Project releases its Top 10 list of the 10 biggest web development mistakes that often lead to security vulnerabilities. Nice idea. But many of the items on the list haven't changed since the 2013 and 2010 reports. In other words, we're still screwing up.

Software developers and testers must be sick of hearing security nuts rant, "Beware SQL injection! Monitor for cross-site scripting! Watch for hijacked session credentials!" I suspect the developers tune us out. Why? Because we've been raving about the same defects for most of their careers. Truth is, though, the same set of major security vulnerabilities persists year after year, decade after decade.

The industry has generated newer tools, better testing suites, Agile methodologies, and other advances in writing and testing software. Despite all that, coders keep making the same dumb mistakes, peer reviews keep missing those mistakes, test tools fail to catch those mistakes, and hackers keep finding ways to exploit those mistakes.

One way to see the repeat offenders is to look at the OWASP Top 10, a sometimes controversial ranking of the 10 primary vulnerabilities, published every three or four years by the Open Web Application Security Project.

The OWASP Top 10 list is not controversial because it's flawed. Rather, some believe that the list is too limited. By focusing only on the top 10 web code vulnerabilities, they assert, it causes neglect for the long tail. What's more, there's often jockeying in the OWASP community about the Top 10 ranking and whether the 11th or 12th belong in the list instead of something else. There's merit to those arguments, but for now, the OWASP Top 10 is an excellent common ground for discussing security-aware coding and testing practices.

Note that the top 10 list doesn't directly represent the 10 most common attacks. Rather, it's a ranking of risk. There are four factors used for this calculation. One is the likelihood that applications would have specific vulnerabilities; that's based on data provided by companies. That's the only "hard" metric in the OWASP Top 10. The other three risk factors are based on professional judgement.

It boggles the mind that a majority of top 10 issues appear across the 2007, 2010, 2013, and draft 2017 OWASP lists.

That doesn't mean that these application security vulnerabilities have to remain on your organization's list of top problems, though—you can swat those flaws.

The draft 2017 OWASP Top 10 list

The OWASP Top 10 list for 2017 is still being compiled. The OWASP community was presented with a "release candidate" Top 10 list, but it was rejected by the community. Still, eight of the entries were left untouched during the community review, meaning they were essentially approved and should appear in the list. The draft contained these:

A1 – Injection Flaws: carried over from 2013

A2 – Broken Authentication & Session Management: carried over from 2013

A3 – Cross-Site Scripting (XSS): carried over from 2013

A4 – Broken Access Control (merges two items from the 2013 top 10: Insecure Direct Object References and Missing Function Level Access Control)

A5 – Security Misconfiguration: carried over from 2013

A6 – Sensitive Data Exposure: carried over from 2013

A7 – Insufficient Preparation for Attacks: a new item in the Top 10

A8 – Cross-Site Request Forgery (CSRF): carried over from 2013

A9 – Using Components with Known Vulnerabilities: carried over from 2013

A10 – Underprotected APIs: a new item in the Top 10

The community voted against accepting two of the draft 2017 entries, A7 and A10. That isn't to say that insufficient preparation for attacks and underprotected APIs aren't security concerns, but rather that they aren't considered to be "Top 10" issues.

It's sad that eight out of 10 of the issues from 2013 are still top security issues in 2017. In fact, if you consider that the draft 2017 list combined two of the 2013 items, it's actually nine out of 10. Ouch.

Let's look at ancient history

The first OWASP Top 10 list was published in 2003, but the terminology changed for the 2007 report. The 2007 OWASP Top 10 list makes for a better apples-to-apples comparison:

A1 – Cross-Site Scripting (XSS): on the 2017 list as A3

A2 – Injection Flaws: on the 2017 list as A1

A3 – Malicious File Execution

A4 – Insecure Direct Object References: on the 2017 list as A4

A5 – Cross-Site Request Forgery (CSRF): on the 2017 list as A8

A6 – Information Leakage and Improper Error Handling

A7 – Broken Authentication and Session Management

A8 – Insecure Cryptographic Storage

A9 – Insecure Communications

A10 – Failure to Restrict URL Access

As you can see, four of these 2007 items are still on the list a decade later, and some of the others have been rolled up into other items.

I'm sure that most developers and testers can intuit the issues on both the 2007 and 2017 lists. We all know not to do these things. So why are they still issues? And in particular, why are we still being killed by issues like injection, XSS, insecure direct object references, and CSRF? Sheesh! Enough already!

Let's look at the first three vulnerabilities on the 2017 list, starting with my "favorite" flaw: injection.

Reject injection or go to jail

In its simplest form, injection means that where you have a data input field, instead of putting the desired data, a hacker inserts something else—JavaScript code, a SQL statement, something. If the web application doesn't validate the input to the application server or database server, there's a chance that the hacker's input could be executed, leading to unpredictable and undesirable results.

Sound theoretical? It's not. My friend Arthur Hicken, the Code Curmudgeon, has a great blog, the "SQLI Hall-of-Shame," that shows real-world examples of hackers successfully injecting SQL statements into deployed web applications. Page after page.

But seriously, how freakin' hard can it be to validate inputs? Apparently, it's too difficult for some developers, especially those who rely upon client-side scripts to do the validation. This is despite the evidence that anything running on a client system can be tricked or subverted. Input validation must be done on the server if it's to have any value. The responsibility for protecting applications must fall on the server-side folks; in a distributed model, any number of web applications—including those from third parties—can access a back-end database or application server.

There is no acceptable excuse for injection. I've heard developers offer one excuse: "My tools should detect injection." No, no, no. It's not the job of the tools—whether an IDE or a security scan run as code is checked into a repository—to ensure that developers don't make stupid mistakes.

Failing to validate inputs and all data submitted by client-side webpages is a stupid mistake. It's tedious, but it must be done—and frankly, managers must be stricter about enforcing the detection of injection by coders and testers. The folks at OWASP have resource pages devoted to preventing injection in general, and its most common form, SQL Injection, in particular.

If you have one software security priority, it should be to squash injection. It's the lowest of low-hanging fruit.

The authentication is broken

Web vulnerability No. 2 is all about broken authentication and session management, which means that a user (or remote server) began a session and possibly authenticated itself for restricted access to resources. Imagine a user going to their bank's website and providing their username and password to access account information and transfer money. What can go wrong? The session might be hijacked.

There are many causes of session hijacking. Perhaps the username and password are sent over plain text and picked up by someone doing a "man in the middle" attack at the local coffee shop. Perhaps session information is stored in URLs, and anyone who can capture the URL can capture the session. Perhaps sessions don't time out, leaving access to the sensitive information open.

The latest from Ponemon — 2016 Cost of Cyber Crime Study & the Risk of Business Innovation Get the Report

Catching and remediating these issues falls on developers, testers, and network administrators. A huge problem here is "roll your own" authentication schemes that use little or poor encryption, too many plain-text files, and clever but easily broken password management. In short, don't do this yourself. Use strong and well-tested authentication and session management controls. If you don't, you're vulnerable. If you do, you're probably very safe.

Cross off the cross-site script

Cross-site scripting (XSS) is somewhat related to injection in that hackers insert malicious client-side scripts (written in languages such as JavaScript) into webpages. An innocent user loads that webpage, and the malicious scripts are executed using the user's privileges. This means that the malicious script can read the user's cookies, session tokens, stored usernames and passwords, or files on a local hard drive.

XSS is harder to prevent than injection, and because it's more of a threat to web users than to web servers, somehow it flies under the radar. The OWASP project suggests the following:

XSS flaws can be difficult to identify and remove from a web application. The best way to find flaws is to perform a security review of the code and search for all places where input from an HTTP request could possibly make its way into the HTML output. Note that a variety of different HTML tags can be used to transmit a malicious JavaScript. Nessus, Nikto, and some other available tools can help scan a website for these flaws, but can only scratch the surface. If one part of a website is vulnerable, there is a high likelihood that there are other problems as well.

XSS is killing us, and it's hard to fight. You need serious training to help your developers, testers, and server administrators fight its scourge. The OWASP's XSS Prevention Cheat Sheet can get you moving in the right direction.

We could go on and on…

Web application vulnerabilities are bad for businesses, and bad for consumers. We've seen huge breaches in web applications that result in huge quantities of stolen data. I'm not saying that all those breaches are caused by organizations failing to address the OWASP Top 10, but these are the biggest issues, by definition.

To use an analogy: There's no point installing a sophisticated alarm system in your car if you fail to lock the door or leave the windows rolled down with the key in the cup holder. Similarly, there's little point worrying about obscure zero-day flaws in your website's firewall if you're not going to block injection, session capture, and XSS.

What can you do? Train everyone better, for starters. Look at coding and test tools that can help detect or prevent security vulnerabilities, but don't consider them silver bullets. Do dynamic application security testing, including penetration testing and fuzz testing. Ensure admins do their part to protect applications. And finally, make sure you establish a culture of security-aware programming and deployment.

Your developers are sick of listening to rants about injection. It's your job to make sure the message has been heard and acted upon.

Software security: Lessons for leaders