как предотвратить SQL-инъекцию - PullRequest
4 голосов
/ 26 января 2011

Я использую хранимые процедуры. Чтобы сэкономить время, я сделал несколько общих процедур, использующих динамический порядок sqlin для обновления. Такая общая процедура:

CREATE PROCEDURE [dbo].[SetField]
 @company_id uniqueidentifier,
 @id bigint,
 @field_code nvarchar(50),
 @value nvarchar(50)
AS
BEGIN
 DECLARE @field_name nvarchar(50)
 SET @field_name = NULL
 SELECT @field_name=field_name
 FROM dbo.FIELD_DEFINITION
 WHERE field_code=@field_code

 IF @field_name IS NOT NULL
 BEGIN

  IF @value IS NULL OR @value=''
  BEGIN
   SET @value='NULL'
  END
  ELSE
  BEGIN
   IF @field_code='START_DATE' OR @field_code='END_DATE'
   BEGIN
    SET @value = CONVERT(datetime, @value ,103)
   END
   SET @value=''''+@value+''''
  END

  DECLARE @sql nvarchar(1000)
  SET @sql = 'UPDATE dbo.TABLE '+
     'SET '+@field_name+'='+@value+' '+
     'WHERE company_id=''' + CAST(@company_id as nvarchar(36)) + ''' AND '+
     'id='+CAST(@id as nvarchar)
  EXEC(@sql)
 END
END

Как я могу предотвратить внедрение SQL с этим кодом?

Ответы [ 3 ]

6 голосов
/ 26 января 2011

Вы сказали:

Чтобы сэкономить время, я сделал несколько общих процедур, использующих динамический sql для обновления

Если бы вы сначала спросили, мы могли бы сэкономить время и предложить это ...

UPDATE
    dbo.TABLE
SET
    Field1 = CASE WHEN @field_name = 'Field1' THEN @value ELSE Field1 END,
    Field2 = CASE WHEN @field_name = 'Field2' THEN @value ELSE Field2 END,
    Field3 = CASE WHEN @field_name = 'Field3' THEN @value ELSE Field3 END,
    ...
    Fieldn = CASE WHEN @field_name = 'Fieldn' THEN @value ELSE Fieldn END
WHERE
    company_id = @company_id AND id = @id
4 голосов
/ 26 января 2011

Важный аспект, который следует помнить о внедрении SQL, заключается в том, что, если это вообще возможно, вы никогда не должны вставлять предоставленные пользователем значения непосредственно в ваш SQL . Это не означает, что вы не можете использовать динамический sql (хотя это определенно упрощает ситуацию, если вы не ), но иногда это становится более опасным.

В вашем конкретном примере вы можете сохранить параметризацию всего, кроме @field_name. К сожалению, это должно быть встроено непосредственно в SQL; все остальное можно снова передать в качестве параметра, поэтому не нужно беспокоиться об их содержимом.

Самое безопасное, что вы можете сделать в этом конкретном примере, это:

if(exists (select 1 from INFORMATION_SCHEMA.Columns where TABLE_NAME = 'Table' and TABLE_SCHEMA = 'dbo' and COLUMN_NAME = @fieldName))
begin
    DECLARE @sql nvarchar(1000)
    SET @sql = 'UPDATE dbo.TABLE '+
       'SET ' + QUOTENAME(@field_name) + '=@value ' + 
       'WHERE company_id=@company_id AND '+
       'id=@id'

    exec sp_executesql @sql,N'@id bigint, @company_id uniqueidentifier, @value nvarchar(50)',@id,@company_id,@value
end

Это делает две вещи:

  1. Он проверяет, что в таблице действительно есть столбец с таким именем. Если бы пользователь вставил в поле любые другие операторы SQL, эта проверка завершилась бы неудачно и оператор не был бы выполнен. Вы также можете позвонить raiseerror, чтобы сообщить об ошибке, но я оставлю это упражнение на ваше усмотрение.
  2. Оно заключает имя поля в квадратные скобки, чтобы имена полей, содержащие пробелы или зарезервированные слова, не нарушали оператор. Это может не быть проблемой для вас, но всегда полезно, если вы сами генерируете SQL.
0 голосов
/ 26 января 2011

Я бы начал искать способы предотвращения атак SQL-инъекций еще до того, как вы вызовете SP.Будьте осторожны с динамическими строками SQL, соединенными из строки запроса или данных формы.Используйте объект SqlCommand .

Редактировать: В ответ на комментарий приведено хорошее объяснение того, как параметризованные запросы (запросы SqlCommand) помогают предотвратить внедрение SQL.

С http://forums.asp.net/t/1568268.aspx:

... Заполнитель - @Id - стал частью жесткого кода SQL.Во время выполнения значение, предоставленное строкой запроса, передается в базу данных вместе с жестко закодированным SQL, и база данных проверяет поле ProductID, когда оно пытается привязать к нему значение параметра.Это обеспечивает уровень строгой типизации.Если значение параметра не является правильным типом для поля базы данных (строка или числовое значение, выходящее за пределы диапазона для типа поля), база данных не сможет преобразовать его в правильный тип и отклонит его.Если тип целевого поля представляет собой строку (char, nvarchar и т. Д.), Значение параметра будет автоматически «строковым», что включает в себя экранирование одинарных кавычек.Он не будет частью выполняемой инструкции SQL.

...