Search code examples
c#sqlado.netoledbsql-injection

In ADO.NET, are there restrictions where SQL parameters can be used in the SQL query?


This question is merely for educational purposes, as I'm not currently building any application that builds SQL queries with user input.

That said, I know that in ADO.NET you can prevent SQL Injection by doing something like this:

OleDbCommand command = new OleDbCommand("SELECT * FROM Table WHERE Account = @2", connection);
command.Parameters.AddWithValue("@2", "ABC");

But assuming that your application is designed in such a way that the user can actually enter the name of the table, can you do the following? (I don't care if it's a bad idea to allow the users to supply the name of the table, I just want to know if the following is possible...)

OleDbCommand command = new OleDbCommand("SELECT * FROM @1 WHERE Account = @2", connection);
command.Parameters.AddWithValue("@1", "Table");
command.Parameters.AddWithValue("@2", "ABC");

I keep getting an exception when I run the second code, saying that the SQL query is incomplete, and I was wondering if the problem is that what I am trying to do simply cannot be done or if I am overlooking something.


Solution

  • No, a query parameter can substitue for one scalar value in your SQL statement.
    For example, a single string literal, a date literal, or a numeric literal.

    It doesn't have to be in the WHERE clause. Anywhere you can have an expression in SQL, you can include a scalar value, and therefore a parameter. For example, in join conditions, or in the select-list, or in ORDER BY or GROUP BY clauses.

    You cannot use query parameters for:

    • Table identifiers
    • Column identifiers
    • SQL keywords
    • SQL expressions
    • Lists of values (for example in an IN() predicate)

    If you need to make any of these parts of your query user-definable, then you need to build the SQL query string by interpolating or concatenating application variables into the string. This makes it difficult to defend against SQL injection.

    The best defense in that case is to whitelist specific values that are safe to interpolate into your SQL string, for instance a set of table names that you define in your code. Let the user choose a table from these pre-approved values, but don't use their input verbatim in SQL code that you then execute.

    User input may provide values, but should never provide code.

    You may find my presentation SQL Injection Myths and Fallacies helpful. I cover whitelisting in that presentation (my examples are in PHP, but the idea applies to any programming language).