Динамический LINQ с прямым вводом данных пользователем, какие опасности?

У меня есть таблица в приложении 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.

Просто уточняю, спасибо :)


person Community    schedule 13.01.2009    source источник


Ответы (3)


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

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

person Rinat Abdullin    schedule 13.01.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));

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

person Rinat Abdullin    schedule 13.01.2009
comment
Я думаю, что это самый подходящий ответ здесь. - person Mark Rogers; 19.11.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 ранее, здесь.

person Marc Gravell    schedule 13.01.2009