Welcome to William's ekasi

[ Log On ]
2011/10/16

I presented two sessions at TechEd Africa this year:

  1. Hack-Proofing your Microsoft ASP.NET Web Forms and MVC Applications
  2. What code-database Gap? Introducing Project Juneau

You can download the slide-decks and code samples for each of the sessions bellow.

Hack-Proofing

Slide Deck

Code Samples

Additional Info:

  • I cover SQL Injection in more detail in a post here.
  • CSRF is covered in more details here.

Juneau

Slide Deck

Sample Database

Feel free to download and use as you wish!

2011/10/16
Tags: Security

Here’s a scary stat for web developers:

19.9% of all web hacks are performed using SQL Injection
Source: http://tinyurl.com/WebHackDB

Stats_thumb3

That’s huge! 1 in every 5 hacks is performed using SQL Injection which worries me, I really thought SQL Injection was a solved problem.

How does it work?

Tarrifs_thumb

SQL Injection works because of the options we have for passing parameters to SQL. The most simple option is where the SQL statement that gets passed to SQL actually includes the text of the parameters. An example of this is shown below:

SQL1_thumb

In this example, the actual SQL statement is being created based on the searchCriteria string parameter. In a normal usage scenario, this would result in a SQL statement being executed by the database that looks something like:

SQL2_thumb

Which is fine for the happy path, but what happens if someone comes along and uses the parameter “Beer’ UNION ALL SELECT * FROM sys.tables;—“? The resulting SQL statement looks drastically different:

SQL3_thumb

This is still perfectly valid SQL and the database engine will execute it exactly as it should (note: this will only work if the columns match up). The database doesn’t know that it’s not supposed to execute the second part of the query. The problem is We haven’t separated the SQL query from the parameter data. We’re treating it all as one. Thankfully, this is an easy fix.

Preventing SQL Injection

The best way to prevent SQL injection is to parameterize your queries. Doing this separates your query from your parameters meaning that SQL will know that regardless of what is passed in as a parameter, it must be treated as a value and not as a potential query. This also has the added benefit of allowing SQL to reuse execution plans (each new parameter in the example above would have to result in a new query plan). Parameterizing your queries is a simple 2-step procedure.

Step 1. Replace the parameter parts of your query with parameter tokens

Our example uses the searchCriteria parameter to build up a string, so instead of changing the string we’re going to replace that section with a token:

SQL4_thumb

Notice how we aren’t passing the parameter in through the string anymore but instead we’re using the @SearchCriteria as part of our string? That’s the token. For each of your parameters, include a unique tokened parameter.

Step 2. Include the parameter’s value in the IDbCommand’s Parameters list

SQL5_thumb

By using the command’s parameter value we have told SQL what the query is as well as what the value of the parameter is and SQL can use that to gain meaning about the query. This means that our query is no longer vulnerable to SQL Injection.

Dynamic SQL

There are times where you need to work with dynamic SQL and this is an often neglected section that isn’t protected from SQL Injection. To protect dynamic SQL from SQL Injection the same solution works: Parameterizing your queries.

Yes, dynamic SQL can also be parameterized – this time, by SQL:

SQL6_thumb

Stored Procedures?

I don’t know where the rumour started about stored procedures being safe from SQL injection, but they aren’t. Stored procedures offer zero protection against SQL Injection!

Here’s an example.

SQL7_thumb

We’re executing a stored procedure here, but we’re still vulnerable to SQL Injection because we’re not separating the parameters from the exec statement. Exactly the same as using normal SQL. Granted, in this case it is more difficult to do SQL injection because of syntax restrictions but this is by no means a solution. The only solution is to again, parameterize it!

In ADO.NET there is a handy property on the IDbCommand object which specifies the query type. If we set the query type to Stored Procedure then ADO.NET forces us to parameterize it. It’s at that point that we get the security we’re looking for.

SQL8_thumb

Notice how here we don’t even have to specify the parameter tokens in the stored procedure name (AddComment)? That’s because ADO.NET tells SQL that we’re executing a particular stored procedure so the parameters have to match up. But remember, the security isn’t coming from the stored procedure – it’s coming from the parameterization!

2010/01/01

ASP.Net MVC includes a Html helper method called AntiForgeryToken.

The AntiForgeryToken is intended to prevent cross site request forgery (CSRF – pronounced Sea-Surf) attacks.  CSRF attacks rely on the fact that the user’s credentials are stored in cookies and are still valid.

While the user’s credentials are still valid at site X, the CSRF attacker will trick the browser to performing actions at site X while the user is browsing a different site.

Example:

William is logged into CodePlex.  The authentication cookie for CodePlex is kept for a really long time and whenever the browser performs requests for CodePlex, the cookie is sent down to the site and CodePlex trusts that William is trying to do something on the forums.

CodePlexToken

So now our requirements are met:

  1. The authentication token is stored in the browser’s cookie
  2. The authentication token is still valid

So how did William get exploited?  Well, it didn’t happen on CodePlex.  William also frequents another forum: The Justin Bieber fanclub forum.  One of the threads William was visiting had a lot of <img /> tags in it.  The source of these tags weren’t all images though.  One of the tags looked like this:

imgtag

And this is where it happened.

The browser saw a request to CodePlex and passed Williams credentials along to CodePlex.  CodePlex said “Ah, you’re William.  He’s cool, we trust him.  Let’s delete everything from OpenPOS like he asked”.

And without even knowing it, William had deleted OpenPOS from CodePlex.

Note: Yes, I know there is no “DeleteEverything” on CodePlex projects.

Prevention:

Preventing this type of attack is incredibly simple in ASP.Net MVC.  There’s a Html helper method called “AntiForgeryToken()” which generates a token.

Usage

The Action method on Controller is then decorated with the ValidateAntiForgeryToken attribute.

Attribute

And that’s it. We’re secured.  But how does this work?

The token that is generated is stored in a hidden form element which is sent down to the browser as part of the markup (similar to the ViewState).  Then, the token is encrypted and that encrypted value is stored in a cookie sent to the user.

AntiForgery

With this set up, each time the form is submitted the cookies value and the hidden form elements values are compared.  If they don’t match, we can assume the request isn’t coming from a valid source and we get a nice error page.

Viewstate

Should this type of error be handled gracefully by your application? I don’t think so. This type of error would result from the values not matching which can either only come from a CSRF attack or the server’s machine key changing during an IIS reset (you do have a machine key defined in your web.config, don’t you?).