Diretrizes de mitigação de ameaças para renderização interativa 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.
Advertência
Esta versão do ASP.NET Core não é mais suportada. Para obter mais informações, consulte a Política de suporte do .NET e .NET Core. 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 como mitigar ameaças à segurança em interações do lado do servidor Blazor.
As aplicações adotam um modelo de processamento de dados stateful , onde o servidor e o cliente mantêm um relacionamento de longa duração. O estado persistente é mantido por um circuito , que pode abranger conexões que também são potencialmente de longa duração.
Quando um usuário visita um site, o servidor cria um circuito na memória do servidor. O circuito indica ao navegador qual conteúdo renderizar e responde a eventos, como quando o usuário seleciona um botão na interface do usuário. Para executar essas ações, um circuito invoca funções JavaScript no navegador do usuário e métodos .NET no servidor. Essa interação bidirecional baseada em JavaScript é conhecida como interoperabilidade JavaScript (JS interop).
Uma vez que a interoperabilidade JS ocorre pela Internet e o cliente usa um navegador remoto, as aplicações web partilham a maioria das preocupações com a segurança. Este tópico descreve ameaças comuns a aplicativos Blazor do lado do servidor e fornece orientações de mitigação de ameaças focadas em aplicativos voltados para a Internet.
Em ambientes restritos, como redes corporativas ou intranets, algumas das orientações de mitigação podem:
- Não se aplica no ambiente restrito.
- Não vale a pena o custo de implementação porque o risco de segurança é baixo em um ambiente restrito.
Componentes interativos do servidor com a compressão do WebSocket ativada
Compressão pode expor a aplicação a ataques de canal lateral contra a criptografia TLS da conexão, como ataques CRIME e BREACH. Estes tipos de ataques exigem que o ciberatacante:
- Forçar um navegador a emitir solicitações com uma carga que o ciberatacante controla para um site vulnerável através de publicação cruzada de formulários ou incorporando o site num iframe de outro site.
- Observe o comprimento da resposta compactada e criptografada pela rede.
Para que o aplicativo seja vulnerável, ele deve refletir a carga do ciberinvasor na resposta, por exemplo, escrevendo o caminho ou a cadeia de caracteres de consulta na resposta. Usando o comprimento da resposta, o ciberatacante pode "adivinhar" qualquer informação sobre a resposta, ignorando a criptografia da conexão.
De um modo geral, as aplicações Blazor podem permitir a compactação na ligação WebSocket com medidas de segurança apropriadas.
O aplicativo pode ficar vulnerável quando pega conteúdo da solicitação (por exemplo, o caminho ou a cadeia de caracteres de consulta) que pode ser influenciado por um invasor cibernético e o reproduz no HTML da página ou o torna parte da resposta.
Blazor aplica automaticamente as seguintes medidas de segurança:
Quando a compactação é configurada, Blazor bloqueia automaticamente a incorporação do aplicativo em um iframe, o que bloqueia a renderização da resposta inicial (descompactada) do servidor e impede que a conexão WebSocket seja iniciada.
A restrição de incorporar o aplicativo em um iframe pode ser relaxada. No entanto, relaxar a restrição expõe o aplicativo a ataques se o documento incorporado for comprometido por meio de uma vulnerabilidade de script entre sites, pois isso dá ao ciberatacante uma maneira de executar o ataque.
Normalmente, para que esse tipo de ataque ocorra, o aplicativo deve reproduzir repetidamente o conteúdo nas respostas para que o ciberatacante possa adivinhar a resposta. Dada a forma como Blazor renderiza (ele renderiza uma vez e, em seguida, produz diffs do conteúdo apenas para os elementos que mudaram), isso é difícil para um ciberatacante realizar. No entanto, não é impossível para um ciberatacante, por isso é preciso ter cuidado para evitar renderizar informações confidenciais ao lado de informações externas que podem ser manipuladas por um ciberatacante. Alguns exemplos disso são:
Renderizar Informações de Identificação Pessoal (PII) na página ao mesmo tempo em que renderiza dados de banco de dados que foram adicionados por outro usuário.
Renderizar informações de identificação pessoal (PII) na página ao mesmo tempo que os dados de um outro utilizador, através de interoperabilidade JS ou de um serviço singleton local no servidor.
Em geral, recomendamos que você evite renderizar componentes que contenham informações confidenciais ao lado de componentes que possam renderizar dados de fontes não confiáveis como parte do mesmo lote de renderização. As fontes não confiáveis incluem parâmetros de rota, cadeias de caracteres de consulta, dados de interoperabilidade JS e qualquer outra fonte de dados que um usuário de terceiros possa controlar (bancos de dados, serviços externos).
Estado compartilhado
Os aplicativos Blazor do lado do servidor vivem na memória do servidor e várias sessões de aplicativos são hospedadas no mesmo processo. Para cada sessão de aplicação, Blazor inicia um circuito com um contêiner de injeção de dependência que tem o seu próprio escopo, pelo que os serviços com escopo são únicos para cada sessão Blazor.
Advertência
Não recomendamos que aplicações no mesmo servidor partilhem estado usando serviços de singleton, a menos que se tenha extremo cuidado, pois isto pode introduzir vulnerabilidades de segurança, como o vazamento do estado do utilizador entre circuitos.
Você pode usar serviços singleton com estado em aplicativos Blazor se eles forem projetados especificamente para isso. Por exemplo, o uso de um cache de memória singleton é aceitável porque um cache de memória requer uma chave para acessar uma determinada entrada. Supondo que os usuários não tenham controle sobre as chaves de cache usadas com o cache, o estado armazenado no cache não vaza entre circuitos.
Para obter orientações gerais sobre a gestão do Estado, consulte ASP.NET Core Blazor State Management.
IHttpContextAccessor
/
HttpContext
em componentes Razor
IHttpContextAccessor deve ser evitado com a renderização interativa porque não existe um HttpContext
válido disponível.
IHttpContextAccessor pode ser usado para componentes que são renderizados estaticamente no servidor. No entanto, recomendamos evitá-lo, se possível.
HttpContext pode ser usado como um parâmetro em cascata somente em componentes raiz renderizados estaticamente para tarefas gerais, como inspecionar e modificar cabeçalhos ou outras propriedades no componente App
(Components/App.razor
). O valor é sempre null
para renderização interativa.
[CascadingParameter]
public HttpContext? HttpContext { get; set; }
Para cenários em que o HttpContext é necessário em componentes interativos, recomendamos a transmissão dos dados através do estado persistente do componente a partir do servidor. Para obter mais informações, consulte ASP.NET Core do lado do servidor e Blazor Web App cenários adicionais de segurança.
Não use IHttpContextAccessor/HttpContext direta ou indiretamente nos componentes Razor de aplicativos Blazor do lado do servidor. As aplicações Blazor são executadas fora do contexto do pipeline do ASP.NET Core. Não é garantido que o HttpContext esteja disponível no IHttpContextAccessore não é garantido que HttpContext mantenha o contexto que iniciou o aplicativo Blazor.
A abordagem recomendada para passar o estado da solicitação para o aplicativo Blazor é por meio de parâmetros de componente raiz durante a renderização inicial do aplicativo. Como alternativa, o aplicativo pode copiar os dados em um serviço com escopo no evento do ciclo de vida de inicialização do componente raiz para uso em todo o aplicativo. Para obter mais informações, consulte ASP.NET Core do lado do servidor e Blazor Web App cenários de segurança adicionais.
Um aspeto crítico da segurança Blazor do lado do servidor é que o utilizador associado a um determinado circuito pode ser atualizado em algum momento depois que o circuito Blazor é estabelecido, mas o IHttpContextAccessornão é atualizado. Para obter mais informações sobre como resolver essa situação com serviços personalizados, consulte ASP.NET Core do lado do servidor e os cenários Blazor Web App de segurança adicionais.
Esgotamento de recursos
O esgotamento de recursos pode ocorrer quando um cliente interage com o servidor e faz com que o servidor consuma recursos excessivos. O consumo excessivo de recursos afeta principalmente:
Os ataques de negação de serviço (DoS) geralmente procuram esgotar os recursos de um aplicativo ou servidor. No entanto, o esgotamento de recursos não é necessariamente o resultado de um ataque ao sistema. Por exemplo, recursos finitos podem ser esgotados devido à alta demanda do usuário. A DoS é abordada mais detalhadamente na seção DoS.
Recursos externos à estrutura Blazor, como bancos de dados e identificadores de arquivo (usados para ler e gravar arquivos), também podem enfrentar esgotamento de recursos. Para obter mais informações, consulte ASP.NET Core Best Practices.
CPU
O esgotamento da CPU pode ocorrer quando um ou mais clientes forçam o servidor a executar trabalho intensivo da CPU.
Por exemplo, considere um aplicativo que calcula um número de Fibonnacci . Um número de Fibonnacci é produzido a partir de uma sequência de Fibonnacci, onde cada número na sequência é a soma dos dois números anteriores. A quantidade de trabalho necessária para chegar à resposta depende do comprimento da sequência e do tamanho do valor inicial. Se o aplicativo não colocar limites na solicitação de um cliente, os cálculos intensivos de CPU podem dominar o tempo da CPU e diminuir o desempenho de outras tarefas. O consumo excessivo de recursos é uma preocupação de segurança que afeta a disponibilidade.
O esgotamento da CPU é uma preocupação para todos os aplicativos voltados para o público. Em aplicações Web normais, os pedidos e as ligações expiram como salvaguarda, mas as aplicações Blazor não fornecem as mesmas salvaguardas. Blazor aplicativos devem incluir verificações e limites apropriados antes de executar um trabalho potencialmente intensivo de CPU.
Memória
O esgotamento da memória pode ocorrer quando um ou mais clientes forçam o servidor a consumir uma grande quantidade de memória.
Por exemplo, considere um aplicativo com um componente que aceita e exibe uma lista de itens. Se o aplicativo Blazor não colocar limites no número de itens permitidos ou no número de itens renderizados de volta ao cliente, o processamento e a renderização com uso intensivo de memória podem dominar a memória do servidor até o ponto em que o desempenho do servidor seja prejudicado. O servidor pode falhar ou abrandar ao ponto de parecer ter falhado.
Considere o seguinte cenário para manter e exibir uma lista de itens que pertencem a um possível cenário de esgotamento de memória no servidor:
- Os itens em uma propriedade ou campo
List<T>
usam a memória do servidor. Se o aplicativo permitir que a lista de itens cresça sem limites, há um risco de o servidor ficar sem memória. A falta de memória faz com que a sessão atual termine (falhe) e todas as sessões simultâneas nessa instância do servidor recebem uma exceção de falta de memória. Para evitar que esse cenário ocorra, o aplicativo deve usar uma estrutura de dados que imponha um limite de itens para usuários simultâneos. - Se um esquema de paginação não for usado para renderização, o servidor usará memória adicional para objetos que não estão visíveis na interface do usuário. Sem um limite no número de itens, as demandas de memória podem esgotar a memória disponível do servidor. Para evitar esse cenário, use uma das seguintes abordagens:
- Use listas paginadas ao renderizar.
- Exiba apenas os primeiros 100 a 1.000 itens e exija que o usuário insira critérios de pesquisa para encontrar itens além dos itens exibidos.
- Para um cenário de renderização mais avançado, implemente listas ou grelhas que suportem a virtualização. Usando a virtualização, as listas renderizam apenas um subconjunto de itens atualmente visíveis para o utilizador. Quando o usuário interage com a barra de rolagem na interface do usuário, o componente renderiza apenas os itens necessários para exibição. Os itens que atualmente não são necessários para exibição podem ser mantidos em armazenamento secundário, que é a abordagem ideal. Itens não exibidos também podem ser mantidos na memória, o que é menos ideal.
Observação
Blazor tem suporte interno para virtualização. Para obter mais informações, consulte ASP.NET Core Razor component virtualization.
Blazor aplicações oferecem um modelo de programação semelhante a outras estruturas de IU para aplicações com estado, como WPF, Windows Forms ou Blazor WebAssembly. A principal diferença é que, em várias das estruturas da interface do usuário, a memória consumida pelo aplicativo pertence ao cliente e afeta apenas esse cliente individual. Por exemplo, um aplicativo Blazor WebAssembly é executado inteiramente no cliente e usa apenas recursos de memória do cliente. Para um aplicativo Blazor do lado do servidor, a memória consumida pelo aplicativo pertence ao servidor e é compartilhada entre clientes na instância do servidor.
As demandas de memória do lado do servidor são uma consideração para todos os aplicativos de Blazor do lado do servidor. No entanto, a maioria das aplicações web é sem estado, e a memória usada durante o processamento de um pedido é liberada quando a resposta é enviada. Como recomendação geral, não permita que os clientes aloquem uma quantidade ilimitada de memória, tal como em qualquer outra aplicação do lado do servidor que mantenha conexões com clientes. A memória consumida por um aplicativo Blazor do lado do servidor persiste por mais tempo do que uma única solicitação.
Observação
Durante o desenvolvimento, pode utilizar-se um profiler ou capturar um rastreamento para avaliar as necessidades de memória dos clientes. Um analisador de perfil ou rastreamento não capturará a memória alocada por um cliente específico. Para capturar o uso de memória de um cliente específico durante o desenvolvimento, capture um dump e examine a demanda de memória de todos os objetos enraizados no circuito de um usuário.
Conexões de cliente
O esgotamento da conexão pode ocorrer quando um ou mais clientes abrem muitas conexões simultâneas com o servidor, impedindo que outros clientes estabeleçam novas conexões.
Blazor clientes estabelecem uma única conexão por sessão e mantêm a conexão aberta enquanto a janela do navegador estiver aberta. Dada a natureza persistente das conexões e a natureza stateful dos aplicativos de Blazor do lado do servidor, o esgotamento da conexão é um risco maior para a disponibilidade do aplicativo.
Não há limite para o número de conexões por usuário para um aplicativo. Se o aplicativo exigir um limite de conexão, siga uma ou mais das seguintes abordagens:
- Requer autenticação, o que naturalmente limita a capacidade de usuários não autorizados de se conectarem ao aplicativo. Para que esse cenário seja eficaz, os usuários devem ser impedidos de provisionar novos usuários sob demanda.
- Limite o número de conexões por usuário. A limitação de conexões pode ser realizada através das seguintes abordagens. Tenha cuidado para permitir que usuários legítimos acessem o aplicativo (por exemplo, quando um limite de conexão é estabelecido com base no endereço IP do cliente).
- Nível de aplicação
- Extensibilidade de roteamento de ponto final.
- Exija autenticação para se conectar ao aplicativo e acompanhar as sessões ativas por usuário.
- Rejeitar novas sessões ao atingir um limite.
- Conexões WebSocket através de um proxy para uma aplicação, como o Azure SignalR Service que multiplexa conexões de clientes para uma aplicação. Isso fornece um aplicativo com maior capacidade de conexão do que um único cliente pode estabelecer, evitando que um cliente esgote as conexões com o servidor.
- Nível do servidor
- Use um proxy/gateway na frente do aplicativo. Por exemplo, o Azure Application Gateway é um balanceador de carga de tráfego web (camada OSI 7) que permite gerir o tráfego para as suas aplicações web. Para obter mais informações, consulte Visão geral do suporte a WebSocket no Application Gateway.
- Embora haja suporte para Long Polling para aplicações Blazor, o que permitiria a adoção do Azure Front Door, o protocolo de transporte recomendado é o WebSockets. A partir de setembro de 2024, Azure Front Door não suporta WebSockets, mas o suporte para WebSockets está em consideração. Para obter mais informações, consulte Suporte para conexões WebSocket no Azure Front Door.
- Nível de aplicação
- Requer autenticação, o que naturalmente limita a capacidade de usuários não autorizados de se conectarem ao aplicativo. Para que esse cenário seja eficaz, os usuários devem ser impedidos de provisionar novos usuários sob demanda.
- Limite o número de conexões por usuário. A limitação de conexões pode ser realizada através das seguintes abordagens. Tenha cuidado para permitir que usuários legítimos acessem o aplicativo (por exemplo, quando um limite de conexão é estabelecido com base no endereço IP do cliente).
- Nível de aplicação
- Extensibilidade de roteamento de ponto final.
- Exija autenticação para se conectar ao aplicativo e acompanhar as sessões ativas por usuário.
- Rejeitar novas sessões ao atingir um limite.
- Encaminhar conexões WebSocket para uma aplicação utilizando um procurador, como o Azure SignalR Service, que multiplexa as conexões dos clientes para uma aplicação. Isso fornece um aplicativo com maior capacidade de conexão do que um único cliente pode estabelecer, evitando que um cliente esgote as conexões com o servidor.
- Nível do servidor
- Use um proxy/gateway na frente do aplicativo.
- Embora Long Polling seja suportado para aplicativos Blazor, WebSockets é o protocolo de transporte recomendado. Recomendamos selecionar um proxy/gateway que suporte WebSockets.
- Nível de aplicação
Ataques de negação de serviço (DoS)
ataques de negação de serviço (DoS) envolvem um cliente fazendo com que o servidor esgote um ou mais dos seus recursos, tornando a aplicação indisponível. Blazor aplicações incluem limites padrão e dependem de outros limites do ASP.NET Core e SignalR que são definidos em CircuitOptions para proteger contra ataques de DoS.
- CircuitOptions.DisconnectedCircuitMaxRetained
- CircuitOptions.DisconnectedCircuitRetentionPeriod
- CircuitOptions.JSInteropDefaultCallTimeout
- CircuitOptions.MaxBufferedUnacknowledgedRenderBatches
- HubConnectionContextOptions.MaximumReceiveMessageSize
Para obter mais informações e exemplos de codificação de configuração, consulte os seguintes artigos:
- ASP.NET de orientação do Core BlazorSignalR
- ASP.NET Core SignalR configuração
Interações com o navegador (cliente)
Um cliente interage com o servidor por meio JS envio de eventos de interoperabilidade e conclusão de renderização. JS interoperabilidade é bidirecional entre JavaScript e .NET.
- Os eventos do navegador são enviados do cliente para o servidor de forma assíncrona.
- O servidor responde de forma assíncrona reprocessando a interface do usuário conforme necessário.
Funções JavaScript invocadas a partir do .NET
Para chamadas de métodos do .NET para o JavaScript:
- Todas as invocações têm um tempo limite configurável após o qual falham, retornando um OperationCanceledException ao chamador.
- Há um tempo limite padrão para as chamadas (CircuitOptions.JSInteropDefaultCallTimeout) de um minuto. Para configurar este limite, consulte Chamar Funções JavaScript a partir de Métodos .NET em ASP.NET Core Blazor.
- Um token de cancelamento pode ser fornecido para controlar o cancelamento por chamada. Confie no tempo limite de chamada padrão sempre que possível e limite de tempo de qualquer chamada para o cliente se um token de cancelamento for fornecido.
- O resultado de uma chamada JavaScript não é confiável. O Blazor cliente de aplicativo em execução no navegador procura a função JavaScript a ser invocada. A função é invocada e o resultado ou um erro é produzido. Um cliente mal-intencionado pode tentar:
- Cause um problema no aplicativo retornando um erro da função JavaScript.
- Induza um comportamento não intencional no servidor retornando um resultado inesperado da função JavaScript.
Tome as seguintes precauções para se proteger contra os cenários anteriores:
- Envolva as chamadas de interoperabilidade JS dentro de instruções
try-catch
para contabilizar erros que possam ocorrer durante as invocações. Para obter mais informações, consulte Manipular erros em aplicações ASP.NET Core Blazor. - Valide os dados retornados de invocações de interoperabilidade JS, incluindo mensagens de erro, antes de executar qualquer ação.
Métodos .NET invocados a partir do navegador
Não confie em chamadas de JavaScript para métodos .NET. Quando um método .NET é exposto ao JavaScript, considere como o método .NET é invocado:
- Trate qualquer método .NET exposto ao JavaScript como se fosse um ponto de extremidade público para o aplicativo.
- Valide a entrada.
- Certifique-se de que os valores estão dentro dos intervalos esperados.
- Verifique se o usuário tem permissão para executar a ação solicitada.
- Não aloque uma quantidade excessiva de recursos como parte da chamada do método .NET. Por exemplo, execute verificações e coloque limites no uso da CPU e da memória.
- Tenha em conta que os métodos estáticos e de instância podem ser expostos a clientes JavaScript. Evite compartilhar o estado entre sessões, a menos que o design exija o estado de compartilhamento com restrições apropriadas.
- Por exemplo, métodos expostos por meio de objetos DotNetObjectReference que são originalmente criados por meio de injeção de dependência (DI), os objetos devem ser registrados como objetos com escopo. Isso se aplica a qualquer serviço de DI que o aplicativo usa.
- Para métodos estáticos, evite estabelecer um estado que não possa ser limitado ao cliente, a menos que o aplicativo, por conceção, esteja explicitamente a partilhar o estado entre todos os utilizadores de uma instância do servidor.
- Evite passar dados fornecidos pelo usuário em parâmetros para chamadas JavaScript. Se a passagem de dados em parâmetros for absolutamente necessária, certifique-se de que o código JavaScript lida com a passagem dos dados sem introduzir scripts entre sites (XSS) vulnerabilidades. Por exemplo, não escreva dados fornecidos pelo usuário no DOM definindo a propriedade
innerHTML
de um elemento. Considere usar de Política de Segurança de Conteúdo (CSP) para desabilitareval
e outras primitivas JavaScript inseguras. Para obter mais informações, consulte Impor uma Política de Segurança de Conteúdo para ASP.NET Core Blazor.
- Valide a entrada.
- Evitar implementar o despacho personalizado de invocações .NET em cima da implementação de despacho do framework. Expor métodos .NET para o navegador é um cenário avançado, não recomendado para desenvolvimento Blazor geral.
Eventos
Os eventos fornecem um ponto de entrada para um aplicativo. As mesmas regras para proteger pontos de extremidade em aplicações web aplicam-se à manipulação de eventos em aplicações Blazor. Um cliente mal-intencionado pode enviar quaisquer dados que deseje enviar como carga útil para um evento.
Por exemplo:
- Um evento de alteração para um
<select>
pode enviar um valor que não está dentro das opções que o aplicativo apresentou ao cliente. - Um
<input>
pode enviar quaisquer dados de texto para o servidor, ignorando a validação do lado do cliente.
O aplicativo deve validar os dados para qualquer evento que o aplicativo manipula. A estrutura Blazorcomponentes de formulários executar validações básicas. Se o aplicativo usa componentes de formulários personalizados, o código personalizado deve ser escrito para validar os dados do evento, conforme apropriado.
Os eventos são assíncronos, portanto, vários eventos podem ser enviados para o servidor antes que o aplicativo tenha tempo para reagir produzindo uma nova renderização. Isto tem algumas implicações de segurança a considerar. A limitação de ações do cliente no aplicativo deve ser executada dentro de manipuladores de eventos e não depende do estado de exibição renderizado atual.
Considere um componente de contador que deve permitir que um usuário incremente um contador no máximo três vezes. O botão para incrementar o contador é condicionalmente baseado no valor de count
:
<p>Count: @count</p>
@if (count < 3)
{
<button @onclick="IncrementCount" value="Increment count" />
}
@code
{
private int count = 0;
private void IncrementCount()
{
count++;
}
}
Um cliente pode despachar um ou mais eventos de incremento antes que a estrutura produza uma nova renderização desse componente. O resultado é que o count
pode ser incrementado mais de três vezes pelo usuário porque o botão não é removido pela interface do usuário com rapidez suficiente. A maneira correta de atingir o limite de três incrementos de count
é mostrada no exemplo a seguir:
<p>Count: @count</p>
@if (count < 3)
{
<button @onclick="IncrementCount" value="Increment count" />
}
@code
{
private int count = 0;
private void IncrementCount()
{
if (count < 3)
{
count++;
}
}
}
Ao adicionar a verificação de if (count < 3) { ... }
dentro do manipulador, a decisão de incrementar count
é baseada no estado atual da aplicação. A decisão não se baseia no estado da interface do usuário, como no exemplo anterior, que pode estar temporariamente obsoleto.
Proteção contra múltiplos despachos
Se um retorno de chamada de evento invocar uma operação de longa execução de forma assíncrona, como buscar dados de um serviço externo ou banco de dados, considere usar uma salvaguarda. A salvaguarda pode impedir que o utilizador enfileire várias operações com feedback visual enquanto a operação está em andamento. O código de componente a seguir define isLoading
para true
enquanto DataService.GetDataAsync
obtém dados do servidor. Enquanto isLoading
está true
, o botão está desativado na interface:
<button disabled="@isLoading" @onclick="UpdateData">Update</button>
@code {
private bool isLoading;
private Data[] data = Array.Empty<Data>();
private async Task UpdateData()
{
if (!isLoading)
{
isLoading = true;
data = await DataService.GetDataAsync(DateTime.Now);
isLoading = false;
}
}
}
O padrão de salvaguarda demonstrado no exemplo anterior funciona se a operação em segundo plano for executada de forma assíncrona com o padrão async
-await
.
Cancele com antecedência e evite o uso após o descarte do objeto
Além de usar uma salvaguarda conforme descrito na seção Protege contra múltiplos despachos, considere usar um CancellationToken para cancelar operações de longa duração ao descartar o componente. Esta abordagem tem a vantagem adicional de evitar uso após descarte nos componentes:
@implements IDisposable
...
@code {
private readonly CancellationTokenSource TokenSource =
new CancellationTokenSource();
private async Task UpdateData()
{
...
data = await DataService.GetDataAsync(DateTime.Now, TokenSource.Token);
if (TokenSource.Token.IsCancellationRequested)
{
return;
}
...
}
public void Dispose()
{
TokenSource.Cancel();
}
}
Evite eventos que produzem grandes quantidades de dados
Alguns eventos DOM, como oninput
ou onscroll
, podem produzir uma grande quantidade de dados. Evite usar esses eventos no servidor Blazor.
Orientações de segurança adicionais
As diretrizes para proteger aplicativos ASP.NET Core aplicam-se a aplicativos Blazor do lado do servidor e são abordadas nas seguintes seções deste artigo:
- Registo e dados sensíveis
- Proteja as informações em trânsito com HTTPS
- de scripts entre sites (XSS)
- Proteção entre origens cruzadas
- Click-jacking
- Abrir redirecionamentos
Registo e dados confidenciais
JS interações de interoperabilidade entre o cliente e o servidor são registradas nos logs do servidor com instâncias ILogger. Blazor evita o registro de informações confidenciais, como eventos reais ou entradas e saídas de interoperabilidade JS.
Quando ocorre um erro no servidor, a estrutura notifica o cliente e destrói a sessão. O cliente recebe uma mensagem de erro genérica que pode ser vista nas ferramentas de desenvolvedor do navegador.
O erro do lado do cliente não inclui a pilha de chamadas e não fornece detalhes sobre a causa do erro, mas os logs do servidor contêm essas informações. Para fins de desenvolvimento, informações de erro confidenciais podem ser disponibilizadas ao cliente por ativando a exibição de erros detalhados.
Advertência
Expor informações de erro a clientes na Internet é um risco de segurança que deve ser sempre evitado.
Proteja as informações em trânsito com HTTPS
Blazor usa SignalR para comunicação entre o cliente e o servidor. Blazor normalmente usa o transporte que SignalR negocia, que normalmente é WebSockets.
Blazor não garante a integridade e confidencialidade dos dados enviados entre o servidor e o cliente. Use sempre HTTPS.
Scripts entre sites (XSS)
O script entre sites (XSS) permite que uma parte não autorizada execute lógica arbitrária no contexto do navegador. Um aplicativo comprometido pode potencialmente executar código arbitrário no cliente. A vulnerabilidade pode ser usada para executar várias ações maliciosas contra o servidor:
- Envie eventos falsos/inválidos para o servidor.
- Falha de envio/conclusões de renderização inválidas.
- Evite despachar finalizações de renderização.
- Envie chamadas de interoperabilidade do JavaScript para o .NET.
- Modifique a resposta de chamadas de interoperabilidade do .NET para JavaScript.
- Evite despachar .NET para resultados de interoperabilidade JS.
A estrutura Blazor toma medidas para proteger contra algumas das ameaças anteriores:
- Interrompe a produção de novas atualizações da interface do usuário se o cliente não estiver reconhecendo lotes de renderização. Configurado com CircuitOptions.MaxBufferedUnacknowledgedRenderBatches.
- Expira qualquer chamada .NET para JavaScript após um minuto sem receber uma resposta do cliente. Configurado com CircuitOptions.JSInteropDefaultCallTimeout.
- Executa a validação básica em todas as entradas provenientes do navegador durante a interoperabilidade JS.
- As referências .NET são válidas e do tipo esperado pelo método .NET.
- Os dados não estão malformados.
- O número correto de argumentos para o método está presente na carga útil.
- Os argumentos ou resultados podem ser desserializados corretamente antes de invocar o método.
- Executa a validação básica em todas as entradas provenientes do navegador a partir de eventos despachados.
- O evento tem um tipo válido.
- Os dados para o evento podem ser desserializados.
- Há um manipulador de eventos associado ao evento.
Além das salvaguardas que a estrutura implementa, o aplicativo deve ser codificado pelo desenvolvedor para se proteger contra ameaças e tomar as ações apropriadas:
- Sempre valide os dados ao manipular eventos.
- Tome as medidas apropriadas ao receber dados inválidos:
- Ignore os dados e retorne. Isso permite que o aplicativo continue processando solicitações.
- Se a aplicação determinar que a entrada é ilegítima e não pôde ser produzida por um cliente legítimo, levante uma exceção. Lançar uma exceção arrebenta o circuito e encerra a sessão.
- Não confie na mensagem de erro fornecida pelas finalizações em lote de renderização incluídas nos logs. O erro é fornecido pelo cliente e geralmente não é confiável, pois o cliente pode estar comprometido.
- Não confie na entrada das chamadas de interoperabilidade JS em ambas as direções entre os métodos JavaScript e .NET.
- O aplicativo é responsável por validar se o conteúdo dos argumentos e resultados são válidos, mesmo que os argumentos ou resultados sejam desserializados corretamente.
Para que exista uma vulnerabilidade XSS, o aplicativo deve incorporar a entrada do usuário na página renderizada.
Blazor executa uma etapa em tempo de compilação onde a marcação em um arquivo .razor
é transformada em lógica C# processual. No tempo de execução, a lógica C# cria uma árvore de renderização, , descrevendo os elementos, o texto e os componentes filhos. Isso é aplicado ao DOM do navegador por meio de uma sequência de instruções JavaScript (ou é serializado para HTML no caso de pré-renderização):
- A entrada do usuário renderizada por meio da sintaxe Razor normal (por exemplo,
@someStringValue
) não expõe uma vulnerabilidade XSS porque a sintaxe Razor é adicionada ao DOM por meio de comandos que só podem escrever texto. Mesmo que o valor inclua marcação HTML, o valor é exibido como texto estático. Durante a pré-renderização, a saída é codificada em HTML, que também exibe o conteúdo como texto estático. - Os autores de componentes podem criar componentes em C# sem usar Razor. O autor do componente é responsável por usar as APIs corretas ao emitir a saída. Por exemplo, use
builder.AddContent(0, someUserSuppliedString)
e nãobuilder.AddMarkupContent(0, someUserSuppliedString)
, pois este último pode criar uma vulnerabilidade XSS.
- A entrada do usuário renderizada por meio da sintaxe Razor normal (por exemplo,
@someStringValue
) não expõe uma vulnerabilidade XSS porque a sintaxe Razor é adicionada ao DOM por meio de comandos que só podem escrever texto. Mesmo que o valor inclua marcação HTML, o valor é exibido como texto estático. Durante a pré-renderização, a saída é codificada em HTML, que também exibe o conteúdo como texto estático. - As tags de script não são permitidas e não devem ser incluídas na árvore de renderização de componentes do aplicativo. Se uma marca de script for incluída na marcação de um componente, um erro em tempo de compilação será gerado.
- Os autores de componentes podem criar componentes em C# sem usar Razor. O autor do componente é responsável por usar as APIs corretas ao emitir a saída. Por exemplo, use
builder.AddContent(0, someUserSuppliedString)
e nãobuilder.AddMarkupContent(0, someUserSuppliedString)
, pois este último pode criar uma vulnerabilidade XSS.
Considere mitigar ainda mais as vulnerabilidades do XSS. Por exemplo, implemente uma CSP (Política de Segurança de Conteúdo) de restritiva. Para obter mais informações, consulte Aplicar uma política de segurança de conteúdo para ASP.NET Core Blazor.
Para obter mais informações, consulte Prevenir Cross-Site Scripting (XSS) no ASP.NET Core.
Proteção entre origens
Os ataques de origem cruzada envolvem um cliente de uma origem diferente executando uma ação contra o servidor. A ação maliciosa normalmente é uma solicitação GET ou um formulário POST (Cross-Site Request Forgery, CSRF), mas abrir um WebSocket mal-intencionado também é possível. Blazor aplicações oferecem as mesmas garantias que qualquer outra aplicação SignalR que utilize o protocolo hub oferece:
- Os aplicativos podem ser acessados entre origens, a menos que medidas adicionais sejam tomadas para evitá-lo. Para desabilitar o acesso entre origens, desabilite o CORS no ponto de extremidade adicionando o Middleware CORS ao pipeline e adicionando o DisableCorsAttribute aos metadados do ponto de extremidade Blazor ou limite o conjunto de origens permitidas configurando SignalR para o Cross-Origin Resource Sharing. Para obter orientação sobre restrições de origem de WebSocket, consulte suporte a WebSockets no ASP.NET Core.
- Se o CORS estiver habilitado, etapas adicionais podem ser necessárias para proteger o aplicativo, dependendo da configuração do CORS. Se o CORS estiver habilitado globalmente, o CORS poderá ser desabilitado para o hub de BlazorSignalR adicionando os metadados DisableCorsAttribute aos metadados do ponto de extremidade depois de chamar MapBlazorHub no construtor de rotas do ponto de extremidade.
Para obter mais informações, consulte Prevenção de ataques de falsificação de solicitações entre sites (XSRF/CSRF) no ASP.NET Core.
Sequestro de clique
O clickjacking envolve renderizar um site como um <iframe>
dentro de um site de uma origem diferente, a fim de enganar o utilizador para realizar ações no site que está sob ataque.
Para proteger um aplicativo contra renderização dentro de um <iframe>
, use de Política de Segurança de Conteúdo (CSP) e o cabeçalho X-Frame-Options
.
Para obter mais informações, consulte os seguintes recursos:
Abrir redirecionamentos
Quando uma sessão de aplicativo é iniciada, o servidor executa a validação básica das URLs enviadas como parte do início da sessão. A estrutura verifica se a URL base é um pai da URL atual antes de estabelecer o circuito. Nenhuma verificação adicional é realizada pela estrutura.
Quando um usuário seleciona um link no cliente, a URL do link é enviada para o servidor, que determina qual ação executar. Por exemplo, o aplicativo pode executar uma navegação no lado do cliente ou indicar ao navegador para ir para o novo local.
Os componentes também podem disparar solicitações de navegação programaticamente através do uso de NavigationManager. Nesses cenários, o aplicativo pode executar uma navegação no lado do cliente ou indicar ao navegador para ir para o novo local.
Os componentes devem:
- Evite usar a entrada do usuário como parte dos argumentos da chamada de navegação.
- Valide argumentos para garantir que o destino seja permitido pelo aplicativo.
Caso contrário, um usuário mal-intencionado pode forçar o navegador a ir para um site controlado por ciberatacantes. Nesse cenário, o ciberatacante engana o aplicativo para usar alguma entrada do usuário como parte da invocação do método NavigationManager.NavigateTo.
Este conselho também se aplica ao renderizar links como parte do aplicativo:
- Se possível, use links relativos.
- Valide se os destinos absolutos do link são válidos antes de incluí-los em uma página.
Para obter mais informações, consulte Impedir ataques de redirecionamento aberto no ASP.NET Core.
Lista de verificação de segurança
A lista de considerações de segurança a seguir não é abrangente:
- Valide argumentos de eventos.
- Valide entradas e resultados de chamadas de interoperabilidade de JS.
- Evite usar (ou validar previamente) a entrada do utilizador para chamadas de interoperabilidade para o .NET para JS.
- Impedir que o cliente aloque uma quantidade ilimitada de memória.
- Dados dentro do componente.
- DotNetObjectReference objetos retornados ao cliente.
- Proteção contra múltiplos despachos.
- Cancele operações de longa duração quando o componente for descartado.
- Evite eventos que produzam grandes quantidades de dados.
- Evite usar a entrada do usuário como parte de chamadas para NavigationManager.NavigateTo e valide a entrada do usuário para URLs em relação a um conjunto de origens permitidas primeiro, se inevitável.
- Não tome decisões de autorização com base no estado da interface do usuário, mas apenas a partir do estado do componente.
- Considere usar a Política de Segurança de Conteúdo (CSP) para proteger contra ataques XSS. Para obter mais informações, consulte Impor uma política de segurança de conteúdo principal para ASP.NET Core Blazor.
- Considere usar CSP e X-Frame-Options para proteger contra clickjacking.
- Verifique se as configurações do CORS são apropriadas ao habilitar o CORS ou desabilitar explicitamente o CORS para aplicativos Blazor.
- Teste para garantir que os limites do lado do servidor para o aplicativo Blazor forneçam uma experiência de usuário aceitável sem níveis inaceitáveis de risco.