I have had several contexts where table names or schemas were not hard-coded, but rather configured by the administrator, or, worse, generated from user input.
Since cases were easy (schemas and table names in plain English, without numbers nor symbols), it was easy to avoid SQL Injection by just forbid any character outside A-Z
and a-z
ranges. But this approach sucks when an application must handle any Unicode characters when can be a part of a name of a schema or a table.
Now, if an SQL query uses '['
and ']'
to include names to schema, table and column, is it enough to forbid only ']'
character in names to avoid SQL Injection?
Example:
A'B is a valid name for a table. So:
string tableNameFromUserInput = "A'B"; // Let's imagine it is a user input.
using (SqlCommand getEverything = new SqlCommand(
string.Format("select * from [dbo].[{0}]", tableNameFromUserInput),
sqlConnection)
{
// Do stuff.
}
is perfectly valid, and there is no reason to block the single quote character.
So is there a risk of SQL Injection in the following code?
string tableName = UserInput.GetUnsafeInputFromUser();
// Search for ']' character only.
if (tableName.IndexOf(']') != -1)
{
throw new HackerDetectedException();
}
else
{
using (SqlCommand getEverything = new SqlCommand(
string.Format("select * from [dbo].[{0}]", tableNameFromUserInput),
sqlConnection)
{
// Do stuff.
}
}
Edit:
After some search, what I found is an article on Delimited identifiers in Microsoft SQL. According to it:
The body of the identifier can contain any combination of characters in the current code page, except the delimiting characters themselves.
By the way, the delimited identifiers are limited to 128 characters.
So to make it work:
- The
']'
character must be forbidden (or, better, replaced by']]'
; see Mark Byers answer below). - The length must be limited to 128 characters (not done in the sample code above),
- The code page must probably be checked to get the correct table.