.Net & SQL Server 2005: предотвращение внедрения при выполнении запросов к списку - PullRequest
0 голосов
/ 08 марта 2012

У меня есть поисковая форма, которая должна запрашивать базу данных SQL Server 2005 другой системы (поэтому я не могу контролировать их хранимые процедуры / функции).

Вообще, чтобы предотвратить инъекцию, мой код будет выглядеть примерно так:

SqlCommand cmd = new SqlCommand("SELECT * FROM myTable WHERE Id = @Id", conn);
cmd.Parameters.AddWithValue("@Id", 1234);

Этот сценарий немного отличается тем, что он запрашивает, чтобы форма позволяла также работать со списком значений через запятую. Итак, как бы я сделал что-то вроде этого:

string ids = "1234, 1235, 1236";
SqlCommand cmd = new SqlCommand("SELECT * FROM myTable WHERE Id IN (" + ids + ")", conn);

Безопасным образом, одним запросом?

Ответы [ 2 ]

2 голосов
/ 08 марта 2012

Существует множество способов передать список и выполнить проверку типов внутри SQL.Если вы используете хранимую процедуру вместо этого специального SQL, вы можете просто передать список в виде строкового параметра и проанализировать его внутри процедуры.Он просто выдаст ошибку, если в списке есть нецелые числа.

Например, эта функция:

CREATE FUNCTION [dbo].[SplitInts]
(
   @List       VARCHAR(MAX),
   @Delimiter  CHAR(1)
)
RETURNS TABLE
AS
   RETURN ( SELECT Item FROM ( SELECT Item = x.i.value('(./text())[1]', 'int') FROM 
            ( SELECT [XML] = CONVERT(XML, '<i>' + REPLACE(@List, @Delimiter, '</i><i>') 
              + '</i>').query('.') ) AS a CROSS APPLY [XML].nodes('i') AS x(i)
          ) AS y WHERE Item IS NOT NULL
   );
GO

Может быть вызвана так:

SELECT Item FROM dbo.SplitInts('1234, 1235, 1236', ',');

Результаты:

Item
----
1234
1235
1236

Если вы пытаетесь использовать какие-либо строки вообще, он взрывается:

SELECT Item FROM dbo.SplitInts('1234; DROP TABLE bobbytables;', ',');

Результат:

Msg 245, Уровень 16, Состояние1, строка 1
Преобразование не выполнено при преобразовании значения nvarchar '1234;DROP TABLE bobbytables; 'к типу данных int.

Таким образом, с этой функцией разделения ваша хранимая процедура может быть записана следующим образом:

CREATE PROCEDURE dbo.GetMyTable
    @List VARCHAR(MAX)
AS
BEGIN
    SET NOCOUNT ON;

    SELECT t.col1, t.col2 --, ...
      FROM dbo.myTable AS t
      INNER JOIN dbo.SplitInts(@List, ',') AS i
      ON t.Id = i.Item;
END
GO

И это можно вызвать из .NET с помощьюстроковый параметр со строгой типизацией @List без каких-либо проблем с внедрением SQL - если вы передадите параметр в правильный вызов с использованием StoredProcedure commandType и не будете пытаться создать строку EXEC ... самостоятельно.

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

0 голосов
/ 08 марта 2012

Это было лучшее решение, которое я мог придумать; если кто-нибудь видит какие-либо уязвимости, пожалуйста, дайте мне знать:

string idList = "1234, 1235, 1236";

XElement ids = new XElement("ds");
foreach (string s in idList.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(id => id.Trim()))
    ids.Add(new XElement("d", s));

SqlCommand cmd = new SqlCommand("SELECT * FROM myTable WHERE Id IN (SELECT T.ids.value('.', 'int') FROM @Ids.nodes('/ds/d') AS T(ids))", conn);
cmd.Parameters.Add(new SqlParameter("@Ids", ids.ToString(SaveOptions.DisableFormatting)) { SqlDbType = SqlDbType.Xml });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...