Dynamic LINQ with direct user input, any dangers?
Asked Answered
S

3

10

I have a table in a ASP.NET MVC application that I want to be sortable (serverside) and filterable using AJAX. I wanted it to be fairly easy to use in other places and didn't feel like hardcoding the sorting and filtering into query expressions so I looked for a way to build the expressions dynamically and the best way to do this I found was with Dynamic LINQ.

User input from a URL like below is directly inserted into a dynamic Where or OrderBy.

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

This would result in two expressions:

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

While I understand that it won't be thrown at the database directly and inserting straight SQL in here won't work because it can't be reflected to a property and it's type-safe and all, I wonder if someone more creative than me could find a way to exploit it regardless. One exploit that I can think of is that it's possible to sort/filter on properties that are not visible in the table, but this isn't that harmful since they still wouldn't be shown and it can be prevented by hashing.

The only way I allow direct user input is with OrderBy and Where.

Just making sure, thanks :)

Serious answered 13/1, 2009 at 11:34 Comment(0)
S
10

Because LINQ to SQL uses type-safe data model classes, you are protected from SQL Injection attacks by default. LINQ to SQL will automatically encode the values based on the underlying data type.
(c) ScottGu

But you can still get "divide by zero" there, so it is recommended to handle all unexpected exceptions and also limit length of the valid entries, JIC

Sera answered 13/1, 2009 at 11:46 Comment(0)
S
9

Hum... I've just found at least one possible issue with the Dynamic Linq. Just exec this snippet 1000 times and watch for the CPU and memory consumption going high up (creating an easy way for the denial of service attack):

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));

I wrote a blog post on that.

Sera answered 13/1, 2009 at 13:8 Comment(1)
I think this is the most relevant answer here.Gonad
F
8

Just a thought, but have you looked at ADO.NET Data Services? This provides a REST-enabled API much like the above with a lot of standard LINQ functionality built in.

I can't think of an interest dynamic LINQ exploit of the top of my head, but if this was me I'd be at least white-listing members (OrderID, CustomerName, etc) - but I'd probably write the Expression logic directly; it isn't especially hard if you are only supporting direct properties.

For example, here is Where (using your Contains logic):

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);
}

I've covered OrderBy previously, here.

Froemming answered 13/1, 2009 at 11:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.