Skip to content
Advertisement

How can I parameterize an SQL table without vulnerability to SQL injection

I’m writing a C# class library in which one of the features is the ability to create an empty data table that matches the schema of any existing table.

For example, this:

The above code works, but it has a glaring security vulnerability: SQL injection.

My first instinct is to parameterize the query like so:

But this leads to the following exception:

Must declare the table variable “@tableName”

After a quick search on Stack Overflow I found this question, which recommends using my first approach (the one with sqli vulnerability). That doesn’t help at all, so I kept searching and found this question, which says that the only secure solution would be to hard-code the possible tables. Again, this doesn’t work for my class library which needs to work for arbitrary table names.

My question is this: how can I parameterize the table name without vulnerability to SQL injection?

Advertisement

Answer

An arbitrary table name still has to exist, so you can check first that it does:

And further, if the list of tables you want to allow the user to select from is known and finite, or matches a specific naming convention (like dbo.Sales%), or belongs to a specific schema (like Reporting), you could add additional predicates to check for those.

This requires you to pass the table name in as a proper parameter, not concatenate or token-replace. (And please don’t use AddWithValue() for anything, ever.)

Once your check that the object is real and valid has passed, then you will still have to build your SQL query dynamically, because you still won’t be able to parameterize the table name. You still should apply QUOTENAME(), though, as I explain in these posts:

So the final code would be something like:

If you also want it to be in some defined list you can add

Or LIKE <some pattern> or join to sys.schemas or what have you.

Provided nobody has the rights to then modify the procedure to change the checks, there is no value you can pass to @TableName that will allow you to do anything malicious, other than maybe selecting from another table you didn’t expect because someone with too much access was able to create before calling the code. Replacing characters like -- or ; does not make this any safer.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement