Breaking Down the OWASP Top 10 2017 RC Part 1: Numbers One Through Five

The Open Web Application Security Project (OWASP) is an open community whose mission is to enable organizations to develop, maintain, and use applications and APIs that can be trusted. They have many great resources for professionals to use to educate themselves on how to build secure web applications.

One of OWASP’s flagship projects is the OWASP Top 10. The Top 10 outlines the top 10 web application vulnerabilities found in the industry. It is based on 11 large datasets provided by companies that specialize in application security. This data allows OWASP to publish the top 10 most troublesome and dangerous vulnerabilities.

The main purpose of the Top 10 is to provide developers, architects, managers, etc. the tools necessary to inspect their own systems for these vulnerabilities as well as properly defend against them. The hope is that those with this knowledge can help to prevent major breaches and exploits in the wild.

Recently OWASP released the OWASP Top 10 2017 Release Candidate (RC) (the previous version is Top 10 2013). It will be open to public comment until June 30 and then a final version will be published in July or August.

A closer look at the Top 10 and what each means for your applications and APIs is warranted. There is certainly much to break down, so I’ll split it into two parts. First, let’s take a look at how the vulnerabilities are rated.

Anatomy of a Top 10 Entry

OWASP has a great diagram that illustrates application security vulnerabilities and how they are exploited. It shows how threat actors use attack vectors against known vulnerabilities in an attempt to exploit them.


Security controls are necessary to mitigate the risks posed by these attacks. OWASP also points out that there are technical and business impacts to exploitation of vulnerabilities.

Each entry on the Top 10 list has associated ratings. Threat agents and business impacts change from business to business. Thus, each individual organization must decide which vulnerabilities are applicable and of the highest risk to it.

The other ratings are shown below. OWASP measures how easily a vulnerability is to find and exploit, as well as how prevalent the error is in current production systems. The technical impact is also rated based on what the attacker can do once a vulnerability is exploited.

An example of high technical impact is SQL injection. SQL injection vulnerabilities can lead to loss of sensitive data such as PII as well as data corruption. That is more severe than an attack where the worst someone can do is deface a website.


With this background, we can now explore each entry on the OWASP Top 10 2017. We’ll discuss what the attack is and how to defend against it.


Injection has been number one on this list from the start, and in 2017 it stays that way. Injection vulnerabilities are still highly prevalent and dangerous, as shown by the OWASP’s rating of it.

As shown below, it is relatively easy to detect, is very common, and very easy to exploit. There are several tools you can find on the internet that will launch such attacks on a website with the click of a button.


The Attack

Injection occurs when untrusted input is executed as a command by an interpreter. Without proper controls in place, an attacker and cause an interpreter to execute arbitrary code from your application.

SQL injection is usually the injection flaw that most think of, but there are other types. OS injection involves trying to invoke OS commands, such as through a command shell, from an application.

A particularly interesting example of injection involved using a malicious JPEG file to arbitrarily execute code in iOS. Many don’t realize that image renderers are actually interpreters that interpret special markup and code inside of the JPEG file to recreate the image. This interpretation has led to vulnerabilities.

For our purposes, we’ll concentrate on SQL injection since this is the most common and exploited injection flaw out there today.

My post on SQL injection goes into some depth on the topic. It is still valuable to outline the main points here.

SQL injection is caused when poor programming practices lead to an attacker executing arbitrary SQL queries against your database. This can result in sensitive data being lost, such as PII or password information. The attacker could also corrupt or destroy data.

Two poor practices that lead directly to SQL injection vulnerabilities are poor input validation and using string concatenation to build queries. Take a look at the code below:


The productSubCategoryId variable is taken directly from a query string and, without any validation, is directly concatenated into a SQL query. With this set up, an attacker could change this query parameter to “1 OR 1=1” and retrieve all records in the table that is being queried.

The Defense

Defending against SQL injection involves two steps. First, validate all input received from the client. Trust nothing.

Second, use parameterized queries or stored procedures. This prevents the data passed in from being treated as a command to be executed.

Since this is number one on the list, architects and developers need to be cognizant of this vulnerability and do everything possible to try to prevent it from creeping into the codebase.

One possible architectural solution would be to create a shared library that exposes an API for database queries. This library can then be made to always execute queries in a safe manner. Distribute this for use by all development teams and you can greatly reduce the risk of injection flaws.

An example of this in the Java world would be Spring Framework’s JdbcTemplate class. This class can be used to create safe, parameterized SQL queries using an API that is easy to use and understand.

In the end, always try to make it easy to be secure.

Broken Authentication and Session Management

Number two on the list is broken authentication and session management. This seems to be another perennial on the Top 10 list.

This is a very prevalent error that leads to severe technical impacts.


Authentication and session management is a major piece of any application. You need to know who your users are. You also need to make sure that your users cannot be impersonated by an attacker.

The Attack

Session management is not an easy problem to solve. HTTP is a stateless protocol. The client sends a request, the server responds, and then the server forgets about you and moves on to the next request.

If another request is sent by your browser, the server has no idea that you are the same person from before. You are just another request to be handled.

Session management is the solution for this problem in wide use today. It involves creating a session ID when a user logs into an application. This session is then passed along with every request. The server then “knows” who you are via your unique session ID.

Broken authentication involves poorly handled user credentials that result in the credentials being lost or stolen. Maybe they are sent over an insecure connection. Maybe they are stored in the database in cleartext or with a weak hash or encryption algorithm.

Whatever the case may be, not securing your user credentials will lead to exploitation. Check out my post on protecting your passwords to see in detail how to properly store passwords in your database.

Another way that session management is done incorrectly is by not protecting that session ID from attackers.

For instance, the session id should never be present in the URL. This makes it trivial for an attacker to steal a session and impersonate a user, or what’s referred to as a session hijacking attack.

The Defense

The first step in defending against this attack is to make sure your user credentials are stored correctly. Also, they should never be transmitted over an insecure connection.

Secondly, session IDs need to be handled with care. Sessions should have a reasonable timeout so that after a certain amount of time the user’s session will be invalidated automatically.

The amount of time should be dictated by business requirements and the sensitivity of the resources begin accessed. When a user logs out, the session needs to be invalidated in the same way.

Third, when a user logs in, a new session ID should be created every time. If the same session is used, it opens up the application to a session fixation attack. An attacker can find the user’s session ID and impersonate the user after tricking the user to log into the application.

The bottom line here is to treat the session ID with the same care as you would other highly sensitive data such as user credentials. Most application frameworks have built-in ways to handle sessions. Take the time to investigate them and choose what is best for your application.

Cross-Site Scripting (XSS)

Number three on the list is cross-site scripting (XSS). XSS is also a repeat offender and was number three on the 2013 Top 10 as well.


This entry is quite interesting, in that its prevalence is listed as very widespread. This shows that this vulnerability can be found all over the web. However, the tools are out there to protect against it.

The Attack

XSS involves an attacker placing malicious code (usually JavaScript) into an input field or URL parameter and having the website execute it. The main place you will find this is with input fields on a form. The attacker enters script into the form and the website executes it.

What can an attacker do with XSS? The applications are broad since the attacker can enter whatever scripts he/she wants. XSS can be used to steal session cookies, deface a website, redirect the browser, or even take advantage of vulnerabilities in the browser to take it over.

There are two types of XSS. The OWASP Top 10 lists them as Stored and Reflected. I have also heard the term Persistent XSS used for what OWASP terms “Stored”.

Stored (or Persistent) XSS occurs when an attacker can cause the application to store an XSS attack in the database. Then whenever that piece of data is retrieved for the UI, the attack is launched.

An example of this is an attacker saving a comment on a blog or other site that is really an XSS attack. The next time someone navigates to that page and pulls back the comments, the XSS attack is launched.

A Reflected XSS attack occurs when user input is “reflected” back to the UI. This can occur if a website takes the user input and places on the page returned when submitted.

Take, for example, a search box that states what you searched for at the top of the results. It may say something like “You searched for <input>”. If the site is vulnerable to XSS, this can be very dangerous.

The Defense

The number one thing developers should remember when dealing with XSS is to always encode your output. This means transforming any markup or script that could be interpreted into an escaped form that will be rendered inert.

For instance, script tags entered into input fields will be presented literally in the browser instead of executing.

Another option is to sanitize the input. Sanitization involves stripping out the bad data that could be interpreted as code.

For instance, if a script tag is entered with the text “alert(‘Hello XSS’);” then the script tag will be stripped out before being returned to the client. This will ensure that the script does not execute.

Encoding and sanitization can also be used in combination for a defense-in-depth strategy.

Sanitization is inherently a ‘black-listing’ approach. It removes known bad values. A clever attacker can usually find inventive and subtle ways to get around sanitization libraries.

If this happens, then encoding and escaping all output will catch anything that sanitization may miss.

Where should this be done, in the client or on the server? Ideally, both the client code and server code should escape and sanitize input.

Many XSS attacks can be done solely on the client side without sending anything to the server.

On the other hand, REST APIs can be called separately from the browser and thus the API code must also validate, sanitize, and encode all input to protect against Stored XSS attacks.

There are many great libraries that one can use to protect against XSS in several languages and frameworks. Some examples are Angular, which encodes all output by default to help protect against XSS.

The Razor view engine in ASP.NET also encodes by default.

Xss-filters is an example of a server-side library for Node.js. Do the research to figure out what tools in your language protect against XSS attacks.

A final and very effective method of protecting against XSS attacks is the use of a Content Security Policy (CSP). A CSP is a special header that can be returned to the browser that instructs the browser from where scripts are allowed to be loaded.

The developer can indicate exactly which domains are allowed to execute script. By default, inline script is not allowed to execute, which will prevent arbitrary script tags from executing if they are placed inside an input field.

Try a defense-in-depth strategy that involves escaping/encoding output, sanitizing input, and a CSP to control which scripts are allowed to execute on your site. Let’s work on lowering the prevalence of this dangerous vulnerability.

Broken Access Control

This is an interesting entry in this year’s list. In the Top 10 for 2013 there were entries for Insecure Direct Object References and Missing Function Level Access Control.

For the 2017 list, these two were combined into Broken Access Control, which sits at number four on the list.

This one is also dangerous. It is easily exploitable, prevalent, and easily detectable. That is a dangerous combination.


Broken access control can be a tricky vulnerability. It involves already authenticated users and making sure they cannot do anything that they shouldn’t.

The Attack

Broken access control comes in two flavors: data references and function calls. Proper authorization is required on both of these in order to be safe from this vulnerability.

Data references refer to a user trying to gain access to a certain piece of data, such as an account or specific object. In the REST service world, this can usually be done by passing an identifier in the URL of the request. Let’s assume a URL like this:

This is referring to the account with an ID of 123. Many applications use a simple sequence number for their IDs. This means when creating records the database will assign the ID starting at one and incrementing by one for each record.

The danger occurs when insufficient access control allows someone to simply guess an ID and then see the details. Consider the above URL being changed to the following:

If this happens in your application, what would happen? If this is a bank account or other source of sensitive information, this could allow an attacker to see the account details of anyone in the system simply by enumerating the values.

They could also build a simple script (I’m thinking a quick bash script with a curl piping to some text file) that will run through a chunk of accounts and pull as much data from them as possible. This could be executed in seconds, leaving your data in unauthorized hands.

Instead, if a user owns account 123, then that user should only be able to see account 123.

There is not necessarily anything wrong with using IDs in URLs, but there is an inherent danger with sequence numbers when there is insufficient access control.

Function calls are another way that insufficient access controls can hurt you.

REST API URLs are not hidden. Attackers can find then and will call them without a browser. Will this work in your application?

Does your application always check for the proper roles and permissions on every function call?

Admin pages should only be used by administrators. Are you able to navigate to an admin page as an anonymous user or as a normal user? This is a great test for you to see how your software reacts.

The Defense

In my blog post on security concepts developers should understand, I speak about a concept called complete mediation.

In a nutshell, complete mediation is the design concept that says every non-public function call (or data reference) has to be authorized. There should not be any way to bypass authorization within your application.

The specific way this is done depends on the implementation technology as well as specific needs and architecture of the organization.

An imperative way of doing this is including a call to an authorization function inside each function that must be protected.

This can work but is more prone to error if you forget it on a key function. It also adds noise to the code as this same call is made in every function.

I prefer a declarative way of including this. Both Java and C# (as examples) support annotations and attributes, respectively. These allow you to decorate functions and classes and these decorations will be checked at runtime and perform a task.

A custom annotation or attribute can be created that will show a specific role required or include a function call to verify access to an account or other object. This works well with many REST frameworks.

It might look like this (in ASP.NET WebAPI):


public HTTPActionResult GetAccount(int id){…}

Java using the Jersey framework would be similar:


public class AccountsResource {




public Response GetAccount(@QueryParam(“id”) int id) {…}

These annotations will then call a central library that checks if a user is authorized to access this function. An exception is raised if the user is not authorized to make this call.

TypeScript also allows the use of annotations. This would allow a similar treatment with a Node.js API as well.

The bottom line is to make it easy to be secure. Have a central function that can be easily invoked by any functions needing authorization.

I like the declarative approach as the developer doesn’t have to think about it too much.

Security Misconfiguration

The fifth entry on the list is Security Misconfiguration. This may not be something that is always on a developer’s mind. However, it can lead to big problems if no one pays attention.


The Attack

Misconfiguration can happen at any level of the architecture. A web server, application server, or database could be configured incorrectly. The OS as well as the application could be at risk.

Unpatched software, such as outdated versions of servers (IIS, Apache, etc) can be exploited. If an attacker can figure out what server version you have, it’s trivial to find out some vulnerabilities and exploit them.

Watch out for default usernames and passwords on both hardware and software. These are known by attackers and  many data breaches are started by an attacker using a default password to get into the network.

Also watch out for ports that are open and in use. Sometimes services are running of which you are not aware. You can be sure that an attacker will find these open ports and use them to get in, especially if they expose a service that is vulnerable to attack.

From a development standpoint, make sure that any error messages shown to the user does not reveal unnecessary information such as stack traces and detailed error information. This can be used by an attacker to know how to better attack your systems.

The Defense

Avoiding misconfiguration comes down to building and maintaining a repeatable process of hardening systems and equipment. If this can be automated, so much the better.

Patch all host OSes and software required to run your application.

Return generic error messages that don’t reveal too much information. The error details can be logged somewhere to be checked by the development team.

Change all default passwords for hardware and software products.

Tools such as Puppet and Chef will definitely come in handy in these situations. If you are using containers, make sure the recipe includes hardening the container to help the application inside to be secure.

There’s Still Five More?!

Yes. There are five more vulnerabilities on the Top 10 list. I’ll cover them in part two. Let’s review what we’ve learned so far.

Injection attacks are still number one. Always sanitize untrusted input and never allow it to execute without parameterization.

Authenticate users correctly and make sure their session IDs and credentials are protected. Always rotate upon login and have sensible timeouts.

Cross-Site Scripting (XSS) can be prevented by sanitizing untrusted input in the client and the server and encoding output to prevent execution.

Use complete mediation to ensure that all function calls and data references are authorized.

Harden all of your systems before putting them into use in a production environment. Try to automate this process if you can.

I’ll see you all back for part two to discuss numbers six through ten!

1 thought on “Breaking Down the OWASP Top 10 2017 RC Part 1: Numbers One Through Five”

  1. Pingback: Breaking Down the OWASP Top 10 2017 RC Part 2: Numbers 6 Through 10 – Green Machine Security

Leave a Reply

%d bloggers like this: