Let’s pretend we’re a nefarious hacker and want to determine what SQL Server logins are available to us on the server. We can use a UNION-based injection attack to query sys.syslogins to get this information and return it as part of the original query:

Blind Injection

A secured server may not allow us to directly output the data we want, but that doesn’t mean we can’t infer certain information.

Normally we pride ourselves in being able to write consistently fast queries. But our dedication to consistently fast executions provides hackers with ways of discerning information without any explicit data output.

For example, let’s say we want to guess if the currently logged in account is “sa”. We can write logic to check this and purposely slow the injectable query’s execution to determine we our guess is correct:

If our query with an expected parameter normally returns in milliseconds, forcing a 5-second delay will indirectly inform us that our guessed “sa” account name is correct.

Protecting Yourself

The easiest way to prevent SQL injection is to avoid using dynamic SQL when it’s unnecessary. In our example stored procedure above, there is no reason we should be using dynamic SQL – this should be a parameterized query that is completely safe from injection attacks:

Finally, make sure the accounts executing your queries have as few allowed permissions as possible. This way, even if your query has an injection vulnerability, the amount of damage an attacker can do is minimal. Many of the examples above would have failed if our account simply didn’t have access to certain system tables or system procedures like xp_cmdshell.

These solutions will not cover every scenario, but they will cover the majority of scenarios and improve our chances of keeping our information secure.

Most ORMs will safely parameterize certain types of queries. The following examples use Entity Framework and SQL Server, but these examples should apply to most other major ORMs and RDBMSs).

Our LINQ query making it easy to access our data layer:

A beautiful, clean, LINQ query

And then the SQL query that our ORM generated.

A query structure that only a mother could love

You’ll notice the generated SQL query is using sp_executesql that has parameterized our input variable value “TFly37”. In this instance we can say the ORM did a good job following best practices in preventing a successful SQL injection attack.

But while ORMs may prevent some SQL injection attempts, there is no guarantee that they will prevent all injection attempts.

What follows are examples of when ORMs can allow for successful injection attacks.

Programatically assembled SQL

ORMs often provide the ability for developers to map the results of adhoc SQL queries to models. Adhoc queries mean potential injection vulnerabilities.

Consider the following:

Looks a lot like your typical SQL injection vulnerability doesn’t it?

Entity Framework, or any ORM for that matter, won’t be able to recognize a parameter concatenated directly into the query string.

Now hopefully the developer has some really strong input validation on the “username” parameter, but the fact still stands: this query is injectable and the ORM will happily execute it.

Stored Procedures

Does the logic needed in your app already exist as a stored procedure?

Parameterized with the value AND datatype – give this developer a raise!

So in this example, the ORM and developer have done everything right. So where’s the injection vulnerability?

Uh oh…

Now let me be clear: this injection vulnerability is not the ORM’s fault.

However, it is the developer’s fault if he is blindly using a procedure without knowing what it does. It’s also the DBA’s fault if she provided an injectable procedure assuming the developer would sanitize any input values in the app.

Security is hard. Everyone needs to work together and be responsible for doing everything within their means to secure their applications.

ORM injection

Technically this isn’t an example of SQL injection.

But that’s why the title of this post says “2.5” instead of “3”.

In this example I’m using a dynamic LINQ to access my data:

Hello concatenation my old friend

If we pass the value \” OR 1 == 1 OR UserName==\” we will have the ORM convert it to the following query:

Game over

Injection takes many forms and doesn’t just come straight from SQL. It’s important to follow best practices in all languages and tools to prevent security incidents.