Part 1: Injection – OWASP Top 10 for EPiServer Developers

Posted on May 22, 2011 by Frederik Vig in ASP.NET, EPiServer

Injection flaws have always been one of the biggest security wholes in web applications. The good news is that it is very easy to protect against them, ones you know how.

So what is injection?

Injection flaws, such as SQL, OS, and LDAP injection, occur when untrusteddata is sent to an interpreter as part of a command or query. The attacker’s hostile data can trick the interpreter into executing unintended commands or accessing unauthorized data.

What this means is that evil input data (from querystrings, form data, HTTP Headers etc) cause your applications queries or commands to change (in a way not designed by you as the developer of the application).

The most common form is SQL injection. Eg:

string query = "SELECT * FROM customers WHERE ID='" + Request["id"];

The attacker can then simple modify either the querystring, form data or the HTTP header collection.

http://example.com/customers?id=’ or ‘1’=’1

This allows the attacker to view the customer information they like, or even go as far as deleting the table (if they run in a user context that has enough database rights).

One way to fix this is to either use parameters or stored procedures:

string query = "SELECT * FROM customers WHERE ID=@id";
SqlCommand command = new SqlCommand(query, connection);
SqlParameter idParameter = new SqlParameter("@id", SqlDbType.Int) { Value = Request["id"] };
 
command.Parameters.Add(idParameter);

This is better, now when someones tries to run http://example.com/app/accountView?id=’ or ‘1’=’1 they’ll get an error (since we’ve defined that id is an integer, ADO.NET takes care of sanitizing the input).

Validate all input

First rule is to always code defensively. An attacker can easily modify everything sent to you, without needing a HTML form. HTTP proxies like Fiddler make this easy. It is much safer for us to whitelist input (specify what we consider valid input), than to blacklist input (specify what is not allowed). The reason for this is simple, you know what is accepted and valid and can make sure that the input matches that pattern. With blacklisting there is a infinitive number of different patterns we’d need to validate against.

In the case above where we accept an ID, which in our case only consists of integers. We can use the int.TryParse() method to validate the input:

int id;
 
if(!int.TryParse(Request.QueryString["id"], out id)
{
  lblMessage.Text = "Invalid customer id.";
  return;
}
 
// valid integer number

Notice that we now only check the querystring (I’m not using Request[“id”] anymore), We also validate and make sure that this is a number. Taking this a step further we could make sure that the number follows a pattern that we’ve defined for customer IDs (at least 4 digits, only positive numbers etc), by using a regular expression.

Dynamic Data Store

With EPiServer CMS 6 came the Dynamic Data Store, (more information on Dynamic Data Store). EPiServer has a factory class for accessing the dynamic data store: DynamicDataStoreFactory. We then use LINQ and Lambda to query the data. If you’ve used ORM tools like NHibernate, LINQ to SQL, Entity Framework etc before this should be familiar. The LINQ and Lambda code then gets translated to SQL code by both using parameters and stored procedures (which protect us against SQL-injections). If you’re curious how this code looks, take a look at the SqlServerDataStoreProvider class in EPiServer.Data.dll.

Always, always use EPiServer’s API when accessing EPiServer data. Not only does it protect against security vulnerbilities like SQL-injection, it also adds smart caching, event notifications and other goodies.

Related Posts: