Tuesday, 6 November 2012

OWASP Top 10: #1 - Injection. How to prevent attack.

This is one in a series of videos and blog posts that explore the top 10 most critical web application security risks as defined by OWASP.
In my previous session, I explained OWASP’s #1 from their top 10  web application security vulnerabilities. Injection.
We saw how easy it is for an attacker to exploit a vulnerable web application.

In this session, I’m going to show you several steps that can be employed to harden your application and mitigate against the threat of injection attack.
You can read the transcript below.
HTML5 player



Transcript



The first action we can take is to apply the “Principle of least privilege”.
Every module in a system must only be able to access the information and resources that are necessary for its legitimate purpose.
As shown in the previous session, the root causes of SQL injection risk are unvalidated input data and a lack of parameterisation.
But the risk was exacerbated because the SQL account the web application used had excessive permissions.
So that’s the first thing I am going to address.
Let me open SQL Server Management Studio 2012 then browse to the database used by the application, 1-Injection.
If I drill down into Security then Users, I can find the user account used by the user account. It too is called 1-Injection.
If I right-click the user account and select Properties then click on Membership I’ll be able to see what roles this user account is a member of. In this case, the user is a member of both db_datareader and db_datawriter. In other words, this user account is able to read from and write to every single table and view in the database.
Now our application is only required to read the Products table. So I’ll uncheck both db_datareader and db_datawriter. And now instead I’ll select Securables and locate the table called Products by clicking on the Search button then choosing All objects of the types.
Once selected, I’ll give the user account the one permission that it requires. And that is Select on the Products table.
So let’s see what effect that has on the application.
If I load up the application in Internet Explorer 10, and then navigate to the Beverages list in the first session, if I attempt to attack this application by injecting some SQL such as:
http://injection/Products.aspx?CategoryID=1 OR 1=(SELECT COUNT(*) FROM Customers)

I should immediately get an error. The reason being that Select permission was denied on the Customers table.
Despite any actions that we subsequently take to prevent SQL injection we can be sure that the web application is only able to access those tables that it is supposed to.
If you recall from the first session, the attacker was able to retrieve customer data with very little difficulty.
A common flaw with web applications is that the developer often takes the contents of the query string and uses it to construct an SQL statement. It is this vulnerability that the attacker is trying to exploit.
A simple step the developer can take to mitigate against this risk is to use inline SQL parameters.
So let me launch Visual Studio 2012 and load up the web application.
The vulnerable page in this application is the Products page, so I’ll load up Products.aspx.cs.
Before we proceed, I need to add a using directive for System.Data.
The next thing I need to do is update the select statement that I am generating behind the scenes.
As you can see, at the moment, I am simply taking the query string parameter and appending it to an SQL statement without first validating it. A better alternative is to update that statement so as to include the parameter. I’ve called the parameter @CategoryID.

Now as my query is being executed by a SQLCommand, I need to notify the command that there is a parameter.
So I put in an additional line of code to add in the @CategoryID parameter to the SQLCommand object and set its value to be the parameter categoryID.
What we are doing here is called parameterisation.
Parameterisation is the practice of separating the query itself from the query parameters. When we do this, it ensures that untrusted data remains data and cannot break out into the query context.
We can parameterise SQL using a number of different approaches. At the moment we are using in-line SQL parameters.
Let me build the project and return to the browser.
I reload the web application and follow the beverages link to navigate to the products page.
If I try to attack this application by updating the query string to CategoryID=1 OR 1=1, unlike in the previous session where no error was returned, this time an error IS returned.
The error occurred as SQL Server will not allow data to enter into the query context and instead will treat the entire string  as a CategoryID and then fail when comparing it to the integer column type .
Another approach when mitigating from the threat of injection is Whitelisting. Implementing a whitelist of acceptable values is a critical mitigation for many security risks.
Whitelisting is the process of saying “This is what I trust”. Blacklisting, on the other hand, says “This is what I don’t trust”.
Blacklisting tends to protect against the risks we know today, but not tomorrow.
White listing is always preferred as its explicit; it says “This is what we know to be safe” rather than “This is what we presently know to be dangerous”.
So let’s implement whitelisting for untrusted data.
Back in Visual Studio 2012, I need to add another using directive to the Products page code behind. This time for System.Text.RegularExpressions.
On the line following that which retrieves the categoryID from the query string, I declare a new variable and assign it an instance of a RegEx regular expression. @"^0*[1-9][0-9]*$". This one designed to identify positive integers.
Below that I can add a test to call the IsMatch method of my regular expression variable passing it the categoryID. And if the categoryID retrieved from the query string does not match the regular expression then we can throw an ApplicationException.
So I’ll build the application and return to Internet Explorer 10. I’ll then click on the Beverages link once again to navigate to the Products page.
This time, if I attack the site by attempting to add in 1=1 to the query string, I’ll see my ApplicationException thrown because the categoryID does not match the regular expression. i.e. it is not a positive integer.
So that’s an example of whitelisting in action. By using a regular expression in this case we have been able to specify exactly what is valid for categoryID.
Let’s try another form of parameterisation. Instead of the inline SQL parameter that we used earlier, this time we’ll use a stored procedure.
So I’ll return to SQL Server Management Studio 2012 and create a new query.
The first thing I need to do is set the database context to be 1-Injection which is the database that the web application uses. And then I can create a stored procedure called GetProducts which can be called by an application rather than it having to create and execute a SELECT statement.
I’ll define a parameter called @CategoryID of type INT and use that parameter in a SELECT statement that is defined within the stored procedure.
One last step that I have to carry out in this script is to grant the Execute permission on the GetProducts stored procedure to the user account named 1-Injection.
In fact before I run this script, I need to add a Go statement between each of those steps.
And finally, I can execute the query to create the stored procedure and grant the execute permission.
Time to return to Visual Studio 2012.
Back in the Products page code behind, I’ll add a statement to parse the parameter passed in from the query string into an integer. We have already established that it is a positive integer thanks to the regular expression.
Now I have written a stored procedure, I no longer require all this code to define an SQL query and execute it via a SQLCommand. So I’ll delete it.
In its place, I’ll put in a new connection and then another SQLCommand object but this time initialised with the name GetProducts.
I’ll set the CommandType to StoredProcedure and remember to add in the parameter @CategoryID.
Once the connection is open, I can execute the command, take the result and place it in the data source of the DataGridView.
All I need to do now is build the project, return to Internet Explorer 10 and load the web application once again.
If I follow the Beverages link, the Products page loads up with a query string containing a CategoryID =1 and displays the results.
Thanks to the combination of actions that I have taken, I can be sure that the risk of SQL injection has been greatly diminished.
Staying with the theme of parameterisation, I could take a third approach. Instead of inline SQL parameters, or stored procedures, I could instead use an Object Relational Mapper – ORM such as Entity Framework or nHibernate.
ORMS generally abstract away the parameterisation.
They represent classes that are added to your program which amongst other things generate safe SQL strings without the need for you to explicitly construct your own.
Let me get back into Visual Studio 2012.
I’ll right-click on the project and select Add New Item.
As I’m choosing to use Entity Framework, I’ll select ADO.NET Entity Data Model.
I’ll name my model, InjectionModel. When the Entity Data Model Wizard appears, I select Generate from database and click Next.
The wizard realises that the application already has a connection string and gives me the option to use that.
For the purposes of the demonstration, I’ll allow sensitive data to be maintained in the connection string. I’ll save the connection string with the name InjectionEntities and once again, click Next.
The wizard then presents me with a list of tables and views that I am able to build my ORM classes from. As the user account only has permission to select from the Products table, that is the only table that I am offered.
I finally provide a meaningful namespace for my classes, in this case InjectionModel and click Finish.
Once Visual Studio 2012 has finished building the ORM classes, a diagram is displayed. In my case, because I was only offered the Products table, only the Product class is shown. In addition to the Product class, Visual Studio 2012 has also created a class named InjectionEntities which represents the database.
Back in the Products page code behind, I can once again remove any unwanted code. This time, I can remove the code that retrieves the connection string from the web.config file and all of the code that I added previously to use the SQLCommand.
In their place, I’m going to declare a new instance of type InjectionEntities, my entity model which is analogous to the database. I then declare a variable called products to which I assign the result of a LINQ statement querying the Products property of the InjectionEntities object. In other words, I am querying the Products table. Albeit indirectly.
I pass into the Where method a lambda expression, selecting the CategoryID that matches the parameter that I retrieved from the query string. As before, the results of the query are simply fed into the DataSource property of the DataGridView control.
So let me build the project one more time, and return back to Internet Explorer 10.
I follow the Beverages link and once again, I am viewing products with a CategoryID of 1. And because Entity Framework uses parameterisation I can be sure that I have mitigated against the threat of SQL injection.
Now in this session we have looked at three ways of implementing parameterisation. Only one would be required. Arguably, it is much easier to implement an ORM such as Entity Framework as it does much of the heavy lifting for you. However, many feel that ORMs suffer from poor performance and query optimisation.
We have looked at a number of approaches in this session. From whitelisting to SQL parameterisation and applying the principle of least privilege. No single approach will mitigate against the threat of injection on its own. Rather it’s a combination of these things. i.e. a layered approach.
In this session we have seen how simple it is to mitigate against the threat of Injection. The #1 in OWASPs top 10 web application security vulnerabilities.

Flash player

Training?

If you are interested in OWASP training, we offer the following courses:


See you soon

Phil Stirpé
"I don't do average!"





1 comment:

  1. The unprecedented level of access points into corporate domains leaves information security professionals turning to a number of data protection methods. Virtual data rooms have been a primary instrument in the information security toolkit for decades.

    ReplyDelete