我可以避免通过WebAPI路由表达式吗? (他们甚至被击溃了吗?)

时间:2017-01-24 21:56:49

标签: c# asp.net-web-api lambda

我的问题

我可以避免通过WebAPI输入参数路由表达式吗?是否有可能发生这种情况?

我的情况(背景)

我有一些与此非常相似的代码(这是一个简化点,使点更清晰):

// DTO Classes:

public abstract class FilterableDtoBase<TEntity>
{
    public string FilterValue { get; set; }
    public abstract Expression<Func<TEntity, bool>> FilterExpression { get; }
    public SortOrder SortOrder { get; set; } // Enum: SortOrder.Ascending, SortOrder.Descending
    public abstract Expression<Func<TEntity, string>> OrderExpression { get; }
}

public class InvoiceByInvoiceNumberFilterableDto: FilterableDtoBase<Invoice>
{
    public Expression<Func<Invoice, bool>> FilterExpression { get; } = i => i.InvoiceNumber.Contains(FilterValue);
    public Expression<Func<Invoice, string>> OrderExpression { get; } => i => i.InvoiceNumber;
}

// In a web API controller class:

[HttpGet]
[Route("invoices/")]
public async Task<Invoice> GetInvoices([FromUri] InvoiceByInvoiceNumberFilterableDto request)
{
    // Simulating EF: myDatamodel.Invoices is IQueryable<Invoice>
    var results = myDatamodel.Invoices.Where(request.FilterExpression);
    if (request.SortOrder == SortOrder.Ascending)
        results = results.SortBy(request.OrderExpression);
    else
        results = results.SortByDescending(request.OrderExpression);

    return results;
}

这背后的目标是双重的:

  • 逻辑可以重复使用,以便我可以通过我的代码库继续添加这些逻辑,而不会对类似的行为重复太多
  • 允许消费者具有一致的FilterValue=x&SortOrder=Ascending行为。

然而,作为这种设计的结果,我意识到我将从请求DTO构造的lambda直接传递到我的模型中,DTO的属性作为任何其他属性暴露给Web API映射。 / p>

问题:

是否可以构造URI / Request主体,以便服务的使用者可以构造任何可以对我使用的lambda表达式?我想知道这是否是WebAPI允许的内容。

例如,有人可以通过这样的方式调用http://example.com/invoices?FilterExpression=Expression.Call(MethodName=SQL,"DROP TABLE")...或表达式,让攻击者控制我的代码吗?

如果是这样,我可以阻止某些属性被Web API路由吗?

更新:我的目标是不允许客户端提交表达式。我的目标是确保不会发生这种情况,这样我就不会暴露自己的安全问题。表达式仅用于从系统中的不同实体抽象过滤器。

1 个答案:

答案 0 :(得分:1)

您可能应该使用其他设计。您的模型FilterableDtoBase应该只包含您希望从请求中获得的字段。

从安全方面来看,我没有看到任何问题。您使用路由的过程实际上是模型绑定。

我们在默认配置中有一些模型绑定器。表达式没有ModelBinder。

你可以使用IModelBinder创建一个自己的Model Binder,它可以支持类似的东西,但是不应该这样做,原因很明显。

最好是Descriptor DTO:

public abstract class FilterableDescriptor
{
    public string FilterValue { get; set; }
    public SortOrder SortOrder { get; set; } // Enum: SortOrder.Ascending, SortOrder.Descending
}

和Extension方法类似:

public static IQueryable ApplyFilter(this IQueryable query, FilterableDescriptor)
{
    //Your logic
    return query;
}

然后你可以这样做:

var results = myDatamodel.Invoices.Where(request.FilterExpression);
return results.ApplyFilter(request);