Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
por Mike Wasson
Este tópico descreve algumas das questões de segurança que deve considerar ao expor um conjunto de dados através do OData para ASP.NET Web API 2 na ASP.NET 4.x.
Segurança EDM
A semântica da consulta baseia-se no modelo de dados da entidade (EDM), não nos tipos de modelo subjacentes. Podes excluir uma propriedade do EDM e ela não será visível para a consulta. Por exemplo, suponha que o seu modelo inclui um tipo de Funcionário com uma propriedade de Salário. Talvez queira excluir esta propriedade do EDM para a ocultar dos clientes.
Existem duas formas de excluir uma propriedade do EDM. Pode definir o atributo [IgnoreDataMember] na propriedade da classe modelo:
public class Employee
{
public string Name { get; set; }
public string Title { get; set; }
[IgnoreDataMember]
public decimal Salary { get; set; } // Not visible in the EDM
}
Também pode remover a propriedade do EDM de forma programática:
var employees = modelBuilder.EntitySet<Employee>("Employees");
employees.EntityType.Ignore(emp => emp.Salary);
Segurança de Consultas
Um cliente malicioso ou ingénuo pode ser capaz de construir uma consulta que demora muito tempo a ser executada. No pior dos casos, isto pode perturbar o acesso ao seu serviço.
O atributo [Queryable] é um filtro de ação que analisa, valida e aplica a consulta. O filtro converte as opções de consulta numa expressão LINQ. Quando o controlador OData retorna um tipo IQueryable , o fornecedor IQueryable LINQ converte a expressão LINQ numa consulta. Portanto, o desempenho depende do fornecedor LINQ utilizado e também das características particulares do seu conjunto de dados ou esquema de base de dados.
Para mais informações sobre o uso de opções de consulta OData na API Web ASP.NET, consulte Suporte a Opções de Consulta OData.
Se souber que todos os clientes são de confiança (por exemplo, num ambiente empresarial), ou se o seu conjunto de dados for pequeno, o desempenho das consultas pode não ser um problema. Caso contrário, deve considerar as seguintes recomendações.
Teste o seu serviço com várias consultas e faça o perfil da base de dados.
Ative a paginação dirigida ao servidor, para evitar devolver um grande conjunto de dados numa única consulta. Para mais informações, consulte Paginação Controlada pelo Servidor.
// Enable server-driven paging. [Queryable(PageSize=10)]Precisas de $filter e $orderby? Algumas aplicações podem permitir a paginação do cliente, usando $top e $skip, mas desativar as outras opções de consulta.
// Allow client paging but no other query options. [Queryable(AllowedQueryOptions=AllowedQueryOptions.Skip | AllowedQueryOptions.Top)]Considere restringir $orderby a propriedades num índice agrupado. Ordenar dados grandes sem um índice agrupado é lento.
// Set the allowed $orderby properties. [Queryable(AllowedOrderByProperties="Id,Name")] // Comma separated listNúmero máximo de nós: A propriedade MaxNodeCount em [Queryable] define o número máximo de nós permitidos na árvore sintáctica $filter. O valor padrão é 100, mas pode querer definir um valor mais baixo, porque um grande número de nós pode ser lento a compilar. Isto é particularmente verdade se estiver a usar LINQ para Objetos (ou seja, consultas LINQ numa coleção na memória, sem o uso de um fornecedor intermédio de LINQ).
// Set the maximum node count. [Queryable(MaxNodeCount=20)]Considere desativar as funções any() e all(), pois estas podem ser lentas.
// Disable any() and all() functions. [Queryable(AllowedFunctions= AllowedFunctions.AllFunctions & ~AllowedFunctions.All & ~AllowedFunctions.Any)]Se alguma propriedade de cadeia contiver cadeias grandes — por exemplo, uma descrição de produto ou uma entrada de blog — considere desativar as funções de cadeia.
// Disable string functions. [Queryable(AllowedFunctions=AllowedFunctions.AllFunctions & ~AllowedFunctions.AllStringFunctions)]Considere não permitir filtragem nas propriedades de navegação. Filtrar as propriedades de navegação pode resultar numa junção, que pode ser lenta, dependendo do esquema da sua base de dados. O código seguinte mostra um validador de consultas que impede a filtragem das propriedades de navegação. Para mais informações sobre validadores de consultas, consulte Validação de Consultas.
// Validator to prevent filtering on navigation properties. public class MyFilterQueryValidator : FilterQueryValidator { public override void ValidateNavigationPropertyNode( Microsoft.Data.OData.Query.SemanticAst.QueryNode sourceNode, Microsoft.Data.Edm.IEdmNavigationProperty navigationProperty, ODataValidationSettings settings) { throw new ODataException("No navigation properties"); } }Considere restringir $filter consultas escrevendo um validador personalizado para a sua base de dados. Por exemplo, considere estas duas consultas:
Todos os filmes com atores cujo apelido começa por 'A'.
Todos os filmes lançados em 1994.
A menos que os filmes sejam indexados por atores, a primeira consulta pode exigir que o motor de base de dados escaneie toda a lista de filmes. Enquanto a segunda pergunta pode ser aceitável, assumindo que os filmes estão indexados por ano de lançamento.
O código seguinte mostra um validador que permite filtrar as propriedades "ReleaseYear" e "Title", mas não outras propriedades.
// Validator to restrict which properties can be used in $filter expressions. public class MyFilterQueryValidator : FilterQueryValidator { static readonly string[] allowedProperties = { "ReleaseYear", "Title" }; public override void ValidateSingleValuePropertyAccessNode( SingleValuePropertyAccessNode propertyAccessNode, ODataValidationSettings settings) { string propertyName = null; if (propertyAccessNode != null) { propertyName = propertyAccessNode.Property.Name; } if (propertyName != null && !allowedProperties.Contains(propertyName)) { throw new ODataException( String.Format("Filter on {0} not allowed", propertyName)); } base.ValidateSingleValuePropertyAccessNode(propertyAccessNode, settings); } }
De um modo geral, considere quais funções $filter necessita. Se os seus clientes não precisarem da expressividade total do $filter, pode limitar as funções permitidas.