Динамический LINQ с прямым пользовательским вводом, какие опасности? - PullRequest
10 голосов
/ 13 января 2009

У меня есть таблица в приложении ASP.NET MVC, которую я хочу сортировать (на стороне сервера) и фильтровать с помощью AJAX. Я хотел, чтобы его было довольно легко использовать в других местах, и мне не хотелось жестко программировать сортировку и фильтрацию в выражениях запросов, поэтому я искал способ динамического построения выражений, и лучший способ сделать это, как я нашел, был с помощью Dynamic LINQ. ,

Пользовательский ввод с URL-адреса, как показано ниже, напрямую вставляется в динамический Where или OrderBy.

/Orders?sortby=OrderID&order=desc&CustomerName=Microsoft

Это приведет к двум выражениям:

OrderBy("OrderID descending")
Where(@"CustomerName.Contains(""Microsoft"")")

Хотя я понимаю, что он не будет добавлен в базу данных напрямую, а вставка прямого SQL-кода здесь не сработает, потому что он не может быть отражен для свойства, и он безопасен от типа, и все, интересно, если кто-то еще Креатив, чем я мог найти способ использовать его независимо. Я могу подумать об одном из них - о том, что можно отсортировать / отфильтровать свойства, которые не видны в таблице, но это не так уж вредно, так как они все равно не будут отображаться, и это можно предотвратить с помощью хеширования.

Единственный способ разрешить прямой ввод данных пользователем - это OrderBy и Where.

Просто убедился, спасибо:)

Ответы [ 3 ]

10 голосов
/ 13 января 2009

Поскольку в LINQ to SQL используются классы модели данных с безопасным типом, по умолчанию вы защищены от атак SQL-инъекций. LINQ to SQL автоматически кодирует значения в зависимости от базового типа данных.
(с) ScottGu

Но вы все равно можете получить «деление на ноль», поэтому рекомендуется обрабатывать все непредвиденные исключения, а также ограничивать длину допустимых записей, JIC

9 голосов
/ 13 января 2009

Хм ... Я только что нашел по крайней мере одну возможную проблему с Dynamic Linq. Просто выполните этот фрагмент 1000 раз и наблюдайте, как сильно увеличивается потребление ресурсов процессора и памяти (создавая простой способ для атаки отказа в обслуживании):

var lambda = DynamicExpression
  .ParseLambda<Order, bool>("Customer=string.Format(\"{0,9999999}"+
     "{0,9999999}{0,9999999}{0,9999999}{0,9999999}\",Customer)")
  .Compile();

var arg = new Order
{
  Total = 11
};
Console.WriteLine(lambda(arg));

Я написал сообщение в блоге об этом.

8 голосов
/ 13 января 2009

Просто мысль, а вы смотрели на ADO.NET Data Services? Это обеспечивает API с поддержкой REST, очень похожий на описанный выше, с множеством встроенных стандартных функций LINQ.

Я не могу представить интересный динамический эксплойт LINQ на макушке головы, но если бы это был я, я был бы как минимум членами белого списка (OrderID, CustomerName и т. д.) - но я бы, вероятно, написал логику Expression напрямую; это не особенно сложно, если вы поддерживаете только прямые свойства.

Например, вот Where (с использованием вашей логики Contains):

static IQueryable<T> Where<T>(this IQueryable<T> source,
    string member, string value)
{
    var param = Expression.Parameter(typeof(T), "x");
    var arg = Expression.Constant(value, typeof(string));
    var prop = Expression.PropertyOrField(param, member);
    MethodInfo method = typeof(string).GetMethod(
        "Contains", new[] { typeof(string) });
    var invoke = Expression.Call(prop, method, arg);
    var lambda = Expression.Lambda<Func<T, bool>>(invoke, param);

    return source.Where(lambda);
}

Я уже рассмотрел OrderBy ранее, здесь .

...