我可以避免通过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路由吗?
更新:我的目标是不允许客户端提交表达式。我的目标是确保不会发生这种情况,这样我就不会暴露自己的安全问题。表达式仅用于从系统中的不同实体抽象过滤器。
答案 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);