Diretrizes de mitigação de ameaças para a renderização estática do lado do servidor do ASP.NET Core Blazor
Observação
Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.
Importante
Estas informações referem-se a um produto de pré-lançamento que pode ser substancialmente modificado antes de ser lançado comercialmente. A Microsoft não oferece garantias, expressas ou implícitas, em relação às informações fornecidas aqui.
Para a versão atual, consulte a versão .NET 9 deste artigo.
Este artigo explica as considerações de segurança que os desenvolvedores devem levar em conta ao desenvolver Blazor Web Apps com renderização estática do lado do servidor.
Blazor combina três modelos diferentes em um para escrever aplicativos Web interativos. Renderização tradicional do lado do servidor, que é um modelo de solicitação/resposta baseado em HTTP. Renderização interativa do lado do servidor, que é um modelo de renderização baseado em SignalR. Finalmente, a renderização do lado do cliente, que é um modelo de renderização baseado em WebAssembly.
Todas as considerações gerais de segurança definidas para os modos de renderização interativos se aplicam aos Blazor Web Apps quando há componentes interativos renderizando em um dos modos de renderização suportados. As seções a seguir explicam as considerações de segurança específicas para a renderização não interativa do lado do servidor em Blazor Web Apps e os aspetos específicos que se aplicam quando os modos de renderização interagem uns com os outros.
Considerações gerais para renderização do lado do servidor
O modelo de renderização do lado do servidor (SSR) é baseado no modelo tradicional de solicitação/resposta do HTTP. Como tal, existem áreas comuns de preocupação entre SSR e HTTP de solicitação/resposta. Considerações gerais de segurança e ameaças específicas devem ser atenuadas com êxito. A estrutura fornece mecanismos internos para gerenciar algumas dessas ameaças, mas outras ameaças são específicas do código do aplicativo e devem ser tratadas pelo aplicativo. Essas ameaças podem ser categorizadas da seguinte forma:
Autenticação e autorização: o aplicativo deve garantir que o usuário esteja autenticado e autorizado a acessar o aplicativo e os recursos que ele expõe. A estrutura fornece mecanismos internos para autenticação e autorização, mas o aplicativo deve garantir que os mecanismos sejam configurados e usados corretamente. Os mecanismos internos de autenticação e autorização são abordados no nó de segurança do
Server da documentação doe no nó de segurança da documentação doASP.NET Core, portanto, não serão abordados aqui. Validação e higienização de entrada: Todas as entradas que chegam de um cliente devem ser validadas e higienizadas antes do uso. Caso contrário, o aplicativo pode ser exposto a ataques, como injeção de SQL, scripts entre sites, falsificação de solicitações entre sites, redirecionamento aberto e outras formas de ataques. A entrada pode vir de qualquer lugar na solicitação.
Gerenciamento de sessão: gerenciar adequadamente as sessões do usuário é fundamental para garantir que o aplicativo não seja exposto a ataques, como fixação de sessão, sequestro de sessão e outros ataques. As informações armazenadas na sessão devem ser devidamente protegidas e criptografadas, e o código do aplicativo deve impedir que um usuário mal-intencionado adivinhe ou manipule sessões.
Tratamento e registo de erros: a aplicação tem de garantir que os erros são devidamente tratados e registados. Caso contrário, o aplicativo pode ser exposto a ataques, como divulgação de informações. Isso pode acontecer quando o aplicativo retorna informações confidenciais na resposta ou quando o aplicativo retorna mensagens de erro detalhadas com dados que podem ser usados para atacar o aplicativo.
Proteção de dados: Os dados confidenciais devem ser devidamente protegidos, o que inclui a lógica do aplicativo ao ser executado no WebAssembly, uma vez que podem ser facilmente submetidos a engenharia reversa.
Negação de serviço: o aplicativo deve garantir que não seja exposto a ataques, como negação de serviço. Isso acontece, por exemplo, quando o aplicativo não está devidamente protegido contra ataques de força bruta ou quando uma ação pode fazer com que o aplicativo consuma muitos recursos.
Validação e higienização de entrada
Todas as entradas que chegam do cliente devem ser consideradas não confiáveis, a menos que suas informações tenham sido geradas e protegidas no servidor, como um token CSRF, um cookiede autenticação, um identificador de sessão ou qualquer outra carga útil protegida com criptografia autenticada.
A entrada normalmente está disponível para o aplicativo por meio de um processo de vinculação, por exemplo, por meio do atributo [SupplyParameterFromQuery]
ou [SupplyParameterFromForm]
atributo. Antes de processar essa entrada, o aplicativo deve certificar-se de que os dados são válidos. Por exemplo, o aplicativo deve confirmar que não houve erros de vinculação ao mapear os dados do formulário para uma propriedade de componente. Caso contrário, o aplicativo pode processar dados inválidos.
Se a entrada for usada para executar um redirecionamento, o aplicativo deverá certificar-se de que a entrada é válida e que não está apontando para um domínio considerado inválido ou para um subcaminho inválido dentro do caminho base do aplicativo. Caso contrário, o aplicativo pode ser exposto a ataques de redirecionamento aberto, onde um ciberinvasor pode criar um link que redireciona o usuário para um site mal-intencionado.
Se a entrada for usada para executar uma consulta de banco de dados, o aplicativo deverá confirmar se a entrada é válida e se não está expondo o aplicativo a ataques de injeção de SQL. Caso contrário, um ciberatacante pode ser capaz de criar uma consulta maliciosa que pode ser usada para extrair informações do banco de dados ou para modificar o banco de dados.
Os dados que podem ter vindo da entrada do usuário também devem ser limpos antes de serem incluídos em uma resposta. Por exemplo, a entrada pode conter HTML ou JavaScript que podem ser usados para executar ataques de script entre sites, que podem ser usados para extrair informações do usuário ou para executar ações em nome do usuário.
A estrutura fornece os seguintes mecanismos para ajudar na validação e higienização de entradas:
- Todos os dados de formulário vinculados são validados para correção básica. Se uma entrada não puder ser analisada, o processo de vinculação relatará um erro que o aplicativo pode descobrir antes de executar qualquer ação com os dados. O componente incorporado EditForm leva isso em consideração antes de invocar a função de retorno do formulário OnValidSubmit. Blazor evita a execução do callback se houver um ou mais erros de ligação.
- A estrutura usa um token antifalsificação para proteger contra ataques de falsificação de solicitação entre sites. Para obter mais informações, consulte ASP.NET de autenticação e autorização do Core Blazor e ASP.NET visão geral dos formulários Core Blazor.
Todas as entradas e permissões devem ser validadas no servidor no momento da execução de uma determinada ação para garantir que os dados sejam válidos e precisos naquele momento e que o usuário tenha permissão para executar a ação. Essa abordagem é consistente com as diretrizes de segurança fornecidas para renderização interativa do lado do servidor.
Gestão de sessões
A gestão de sessão é tratada pelo framework. A estrutura usa uma sessão cookie para identificar a sessão do utilizador. A sessão cookie é protegida usando as APIs de proteção de dados do ASP.NET Core. A sessão cookie não é acessível ao código JavaScript em execução no navegador e não pode ser facilmente adivinhada ou manipulada por um utilizador.
No que diz respeito a outros dados de sessão, como dados armazenados em serviços, os dados de sessão devem ser armazenados em serviços com escopo, pois os serviços com escopo são exclusivos por uma determinada sessão de usuário, em oposição aos serviços singleton que são compartilhados em todas as sessões de usuário em uma determinada instância de processo.
Quando se trata de SSR, não há muita diferença entre serviços com escopo e transitórios na maioria dos casos, já que o tempo de vida do serviço é limitado a uma única solicitação. Há uma diferença em dois cenários:
- Se o serviço for injetado em mais de um local ou em momentos diferentes durante a solicitação.
- Se o serviço puder ser usado num contexto de servidor interativo, onde sobrevive a múltiplas renderizações, é fundamental que o serviço tenha escopo para a sessão do usuário.
Tratamento e registo de erros
A estrutura fornece registo de logs integrado para a aplicação ao nível do framework. A estrutura registra eventos importantes, como quando o token antifalsificação de um formulário não é validado, quando um componente raiz começa a renderizar e quando uma ação é despachada. O aplicativo é responsável por registrar quaisquer outros eventos que possam ser importantes para gravar.
A estrutura fornece tratamento de erros interno para o aplicativo no nível da estrutura. A estrutura lida com erros que acontecem durante a renderização de um componente e usa o mecanismo de limite de erro para exibir uma mensagem de erro amigável ou permite que o erro borbulhe até o middleware de tratamento de exceções, que é configurado para renderizar a página de erro.
Os erros que ocorrem durante a renderização de streaming depois que a resposta começou a ser enviada ao cliente são exibidos na resposta final como uma mensagem de erro genérica. Os detalhes sobre a causa do erro só são incluídos durante o desenvolvimento.
ASP.NET Proteção de dados principais
A estrutura oferece mecanismos para proteger informações confidenciais para uma determinada sessão de usuário e garante que os componentes internos usem esses mecanismos para proteger informações confidenciais, como proteger a identidade do usuário ao usar autenticação cookie. Fora dos cenários manipulados pela estrutura, o código do desenvolvedor é responsável por proteger outras informações específicas do aplicativo. A maneira mais comum de fazer isso é por meio das APIs ASP.NET Core Data Protection (DP) ou qualquer outra forma de criptografia. Como regra geral, o aplicativo é responsável por:
- Certificar-se de que um usuário não pode inspecionar ou modificar as informações privadas de outro usuário.
- Certificar-se de que um usuário não pode modificar dados de outro usuário, como um identificador interno.
Com relação ao DP, você deve entender claramente onde o código está sendo executado. Para a renderização estática do lado do servidor (SSR estático) e a renderização interativa do lado do servidor (SSR interativo), o código é armazenado no servidor e nunca chega ao cliente. Para o modo de renderização Interactive WebAssembly, o código do aplicativo sempre chega aodo cliente, o que significa que qualquer informação confidencial armazenada no código do aplicativo está disponível para qualquer pessoa com acesso ao aplicativo. A ofuscação e outras técnicas semelhantes para "proteger" o código não são eficazes. Uma vez que o código chega ao cliente, ele pode ser revertido para extrair as informações confidenciais.
Negação de serviço
No nível do servidor, a estrutura fornece limites nos parâmetros de solicitação/resposta, como o tamanho máximo da solicitação e o tamanho do cabeçalho. Em relação ao código do aplicativo, o sistema de mapeamento de formulários do Blazordefine limites semelhantes aos definidos pelo sistema de vinculação do modelo MVC:
- Limite do número máximo de erros.
- Limite da profundidade máxima de recursão para o aglutinante.
- Limite do número máximo de elementos vinculados em uma coleção.
Além disso, há limites definidos para o formulário, como o tamanho máximo da chave do formulário e o tamanho do valor e o número máximo de entradas.
Em geral, o aplicativo deve avaliar quando há uma chance de que uma solicitação acione uma quantidade assimétrica de trabalho pelo servidor. Exemplos disso incluem quando o usuário envia uma solicitação parametrizada por N e o servidor executa uma operação em resposta que é N vezes mais cara, onde N é um parâmetro que um usuário controla e pode crescer indefinidamente. Normalmente, o aplicativo deve impor um limite ao N máximo que está disposto a processar ou garantir que qualquer operação seja menor, igual ou mais cara do que a solicitação por um fator constante.
Este aspeto tem mais a ver com a diferença de crescimento entre o trabalho que o cliente executa e o trabalho que o servidor executa do que com uma comparação específica de 1→N. Por exemplo, um cliente pode enviar um item de trabalho (inserir elementos em uma lista) que leva N unidades de tempo para ser executado, mas o servidor precisa de N2 para processar (porque pode estar fazendo algo muito ingênuo). É a diferença entre N e N2 que importa.
Como tal, há um limite de quanto trabalho o servidor deve estar disposto a fazer, que é específico para o aplicativo. Esse aspeto se aplica a cargas de trabalho do lado do servidor, uma vez que os recursos estão no servidor, mas não se aplica necessariamente às cargas de trabalho WebAssembly no cliente na maioria dos casos.
O outro aspeto importante é que isso não é reservado apenas ao tempo da CPU. Ele também se aplica a quaisquer recursos, como memória, rede e espaço no disco.
Para cargas de trabalho WebAssembly, geralmente há pouca preocupação com a quantidade de trabalho que o cliente executa, uma vez que o cliente é normalmente limitado pelos recursos disponíveis no cliente. No entanto, existem alguns cenários em que o cliente pode ser afetado, se, por exemplo, um aplicativo exibe dados de outros usuários e um usuário é capaz de adicionar dados ao sistema que força os clientes que exibem os dados a executar uma quantidade de trabalho que não é proporcional à quantidade de dados adicionados pelo usuário.
Lista de verificação recomendada (não exaustiva)
- Certifique-se de que o usuário está autenticado e autorizado a acessar o aplicativo e os recursos que ele expõe.
- Valide e limpe todas as entradas provenientes de um cliente antes de usá-las.
- Gerencie adequadamente as sessões do usuário para garantir que o estado não seja compartilhado por engano entre os usuários.
- Manipule e registre erros corretamente para evitar a exposição de informações confidenciais.
- Registre eventos importantes no aplicativo para identificar possíveis problemas e auditar ações executadas pelos usuários.
- Proteja informações confidenciais usando o ASP.NET Core Data Protection APIs ou um dos componentes disponíveis (Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage, PersistentComponentState).
- Certifique-se de que o aplicativo compreende os recursos que podem ser consumidos por uma determinada solicitação e tem limites em vigor para evitar ataques de negação de serviço.