Запрос с динамическим именем таблицы - PullRequest
0 голосов
/ 19 июня 2019

Я хотел бы изменить динамический оператор SQL в параметризованном операторе, но в запросе имя таблицы является динамическим. Таким образом, я попытался описать все утверждение таким образом, как я видел в ответе нового CRM поддержки в по этой ссылке :

command.CommandType = CommandType.Text;

string sqlStr = " DECLARE @sqlSubstr nvarchar(max) SET @sqlSubstr = N'UPDATE quotename(@tempTable) = SET @flag = 1 WHERE @tempCol = @tempColVal' EXECUTE sp_executesql @sqlSubstr";
command.CommandText = sqlStr;
command.Parameters.AddWithValue("@tempTable", TemporaryTableName);
command.Parameters.AddWithValue("@flag", flagToUpdate);
command.Parameters.AddWithValue("@tempCol", ImportRegister.TemporaryTableKeyColumn);
command.Parameters.AddWithValue("@tempColVal", sourceRow[ImportRegister.TemporaryTableKeyColumn]);
command.ExecuteNonQuery();

Но когда я запускаю его, у меня есть исключение. «Должен объявить переменную calar @tempTable», и я не могу понять, что мне не хватает. Спасибо

1 Ответ

1 голос
/ 19 июня 2019

Использование такого динамического SQL - признак плохого дизайна, как в дизайне базы данных, так и в дизайне приложения.

Однако, предполагая, что дизайн не может быть изменен, проблема с вашим текущим оператором SQL заключается в том, что вы фактически не используете динамический SQL.
Динамический SQL для этого будет выглядеть следующим образом:

DECLARE @sqlSubstr nvarchar(max) = N'UPDATE '+ quotename(@tempTable) +N' 
    SET '+ quotename(@flag) +N' = 1 
    WHERE '+ quotename(@tempCol) +' = @tempColVal;

EXECUTE sp_executesql @sqlSubstr, N'@tempColVal varchar(2)', @tempColVal;

Обратите внимание, что параметры для имени таблицы и имен столбцов объединяются в строку, представляющую SQL, который вы выполняете.
Также обратите внимание, что я добавил quotename и к именам столбцов.

Однако я не уверен, что это обеспечивает полную защиту от атак SQL-инъекций.Использование quotename действительно обеспечивает некоторую защиту, но я уверен, что это можно преодолеть.
Чтобы по-настоящему защитить себя, вы должны внести в белый список все идентификаторы - поэтому сначала вам нужно запросить information_schema.columns, чтобыубедитесь, что все безопасно.

Только после этого вы можете быть уверены, что код безопасен для SQL-инъекций.Пока мы на этом, , вам действительно следует прекратить использовать AddWithValue.

Вот пересмотренная версия вашего кода:

string sqlStr = @"DECLARE @sqlSubstr nvarchar(max) = 
    N'UPDATE '+ quotename(@tempTable) +
    N' SET '+ quotename(@flag) +
    N' = 1 WHERE '+ quotename(@tempCol) +' = @tempColVal' 
    IF EXISTS(
        -- make sure both columns exists in the table
        SELECT 1
        FROM Information_schema.Columns
        WHERE Table_Name = @tempTable
        AND Column_Name IN(@flag, @tempCol)
        HAVING COUNT(DISTINCT Column_Name) = 2 
    )
    EXECUTE sp_executesql @sqlSubstr N'@tempColVal nvarchar' @tempColVal"; -- I had to guess the data type

command.CommandText = sqlStr;
command.Parameters.Add("@tempTable", SqlDbType.NVarChar).Value = TemporaryTableName;
command.Parameters.Add("@flag", SqlDbType.NVarChar).Value = flagToUpdate;
command.Parameters.Add("@tempCol", SqlDbType.NVarChar).Value = ImportRegister.TemporaryTableKeyColumn;
command.Parameters.Add("@tempColVal", SqlDbType.NVarChar).Value = sourceRow[ImportRegister.TemporaryTableKeyColumn]);
command.ExecuteNonQuery();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...