SQL Server: очистка @param от инъекционных атак - PullRequest
7 голосов
/ 01 апреля 2009

Ради аргумента давайте просто скажем, что я должен создать локальную переменную, содержащую запрос SQL, который имеет INSERT:

 DECLARE @insert NVARCHAR(MAX)
 SELECT @insert = 'INSERT INTO [dbo].[' + @table + '] VALUES...
 EXEC (@insert) 

Этот INSERT также будет содержать значение столбца:

 DECLARE @insert NVARCHAR(MAX)
 SELECT @insert = 
  'INSERT INTO [dbo].[' + @table + '] VALUES (N''' + @message + ''')'
 EXEC (@insert) 

Теперь я явно обеспокоен атакой с помощью инъекций и хотел бы убедиться, что значение @ message не может сделать значение @ insert злонамеренным или искаженным как запрос к EXEC.

Это подводит нас к моему вопросу: достаточно ли экранирования 'символов в @message? Есть ли другие символы, которые могли бы появиться в @message, которые могли бы исчезнуть?

Пример:

 DECLARE @insert NVARCHAR(MAX)
 SELECT @message = REPLACE(@message,'''','''''')
 SELECT @insert = 
  'INSERT INTO [dbo].[' + @table + '] VALUES (N''' + @message + ''')'
 EXEC (@insert)  

(Когда я говорю " должен ", это потому, что мой запрос находится в хранимой процедуре, и эта хранимая процедура принимает @table, которая является таблицей назначения, в которую нужно вставить INSERT. Я не интересно обсудить мою архитектуру или почему таблица для INSERT "динамически" указывается с помощью параметра процедуры. Пожалуйста, воздержитесь от комментирования этого , если кроме EXEC () нет другого способа запроса таблицы для указания INSERT, когда затем имя таблицы принимается в качестве параметра процедуры .)

Ответы [ 4 ]

10 голосов
/ 01 апреля 2009

Используйте sp_executesql и встроенный quotename(). Эта статья, Проклятие и благословения динамического SQL , является в значительной степени окончательной ссылкой.

1 голос
/ 01 апреля 2009

Сначала вы можете запросить информацию о схеме с помощью обычного T-SQL и убедиться, что имя таблицы существует первым. Таким образом, если это неправильно сформированный SQL, он не будет выполняться как код. Это будет просто имя таблицы VARCHAR.

DECLARE @Table AS VARCHAR(MAX)
DECLARE @Exists AS BIT

SET @Table = 'Vicious malformed dynamic SQL'

SELECT  @Exists = COUNT(TABLE_NAME) 
FROM    INFORMATION_SCHEMA.TABLES 
WHERE   TABLE_NAME = @Table

IF (@Exists = 1)
    BEGIN
    PRINT 'Table exists'
    -- Execute dynamic SQL.
    END
ELSE
    PRINT 'Invalid table'

(или просто использовать IF EXISTS (SELECT ....))

1 голос
/ 01 апреля 2009

Вместо вызова EXEC (@somesql) я предлагаю использовать хранимую процедуру sp_executesql . В частности, это позволяет передавать параметры, и система проверит правильность параметров.

0 голосов
/ 01 апреля 2009

Очевидно, что для quotename () существует ограничение в 128 длин, даже в 2008 году, согласно моему тесту, поскольку он ожидает идентификатор SQL. Ссылка предлагает создать функцию quotestring () , которая делает то же самое, что и:

REPLACE(@variable,'''','''''')

Поэтому я предлагаю создать ответ из функции REPLACE () выше, например, так:

CREATE FUNCTION quotestring(@string nvarchar(MAX)) 
RETURNS nvarchar(MAX) AS
BEGIN
    RETURN(REPLACE(@string,'''',''''''))
END

... Если я что-то не так понял.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...