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

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

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

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

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

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

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

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

Просто убедившись, спасибо:)

Ответ 1

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

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

Ответ 2

Hum... Я только что нашел хотя бы одну возможную проблему с 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));

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

Ответ 3

Просто мысль, но вы посмотрели 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 ранее, здесь.