Impedir ataques de XSRF/CSRF (solicitação entre sites) em ASP.NET Core

Por Fiyaz Hasan, Rick Anderson e Steve Smith

A falsificação de solicitação entre sites (também conhecida como XSRF ou CSRF) é um ataque contra aplicativos hospedados na Web em que um aplicativo Web mal-intencionado pode influenciar a interação entre um navegador cliente e um aplicativo Web que confia nesse navegador. Esses ataques são possíveis porque os navegadores da Web enviam alguns tipos de tokens de autenticação automaticamente com cada solicitação para um site. Essa forma de exploração também é conhecida como um ataque de um clique ou uma corrida de sessão porque o ataque aproveita a sessão autenticada anteriormente do usuário.

Um exemplo de um ataque CSRF:

  1. Um usuário entra usando www.good-banking-site.com a autenticação de formulários. O servidor autentica o usuário e emite uma resposta que inclui uma autenticação cookie. O site está vulnerável a ataques porque confia em qualquer solicitação recebida com uma autenticação cookieválida.

  2. O usuário visita um site mal-intencionado. www.bad-crook-site.com

    O site www.bad-crook-site.commal-intencionado contém um formulário HTML semelhante ao seguinte exemplo:

    <h1>Congratulations! You're a Winner!</h1>
    <form action="https://good-banking-site.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

    Observe que as postagens do action formulário para o site vulnerável, não para o site mal-intencionado. Essa é a parte "entre sites" do CSRF.

  3. O usuário seleciona o botão Enviar. O navegador faz a solicitação e inclui automaticamente a autenticação cookie para o domínio solicitado. www.good-banking-site.com

  4. A solicitação é executada no www.good-banking-site.com servidor com o contexto de autenticação do usuário e pode executar qualquer ação que um usuário autenticado tenha permissão para executar.

Além do cenário em que o usuário seleciona o botão para enviar o formulário, o site mal-intencionado pode:

  • Execute um script que envia automaticamente o formulário.
  • Envie o envio do formulário como uma solicitação AJAX.
  • Oculte o formulário usando CSS.

Esses cenários alternativos não exigem nenhuma ação ou entrada do usuário além de visitar inicialmente o site mal-intencionado.

O uso de HTTPS não impede um ataque CSRF. O site mal-intencionado pode enviar uma solicitação https://www.good-banking-site.com/ tão facilmente quanto pode enviar uma solicitação insegura.

Alguns ataques têm como alvo pontos de extremidade que respondem a solicitações GET, nesse caso, uma marca de imagem pode ser usada para executar a ação. Essa forma de ataque é comum em sites de fórum que permitem imagens, mas bloqueiam JavaScript. Os aplicativos que alteram o estado em solicitações GET, em que variáveis ou recursos são alterados, são vulneráveis a ataques mal-intencionados. Solicitações GET que alteram o estado são inseguras. Uma prática recomendada é nunca alterar o estado em uma solicitação GET.

Ataques CSRF são possíveis em aplicativos Web que usam cookies para autenticação porque:

  • Repositórios cookiede navegadores emitidos por um aplicativo Web.
  • Os armazenamentos cookieincluem sessões cookiepara usuários autenticados.
  • Os navegadores enviam todos os cookies associados a um domínio para o aplicativo Web a cada solicitação, independentemente de como a solicitação para o aplicativo foi gerada dentro do navegador.

No entanto, os ataques CSRF não se limitam à exploração cookiede s. Por exemplo, a autenticação Básica e Digest também é vulnerável. Depois que um usuário entra com a autenticação Básica ou Digest, o navegador envia automaticamente as credenciais até que a sessão termine.

Nesse contexto, a sessão refere-se à sessão do lado do cliente durante a qual o usuário é autenticado. Não está relacionado a sessões do lado do servidor ou ASP.NET Core Middleware de Sessão.

Os usuários podem se proteger contra vulnerabilidades CSRF tomando precauções:

  • Saia de aplicativos Web quando terminar de usá-los.
  • Limpe o navegador cookieperiodicamente.

No entanto, as vulnerabilidades CSRF são fundamentalmente um problema com o aplicativo Web, não com o usuário final.

Conceitos básicos sobre autenticação

CookieA autenticação baseada é uma forma popular de autenticação. Os sistemas de autenticação baseados em token estão crescendo em popularidade, especialmente para SPAs (Aplicativos de Página Única).

Quando um usuário autentica usando seu nome de usuário e senha, ele é emitido um token, contendo um tíquete de autenticação que pode ser usado para autenticação e autorização. O token é armazenado como um cookie que é enviado a cada solicitação que o cliente faz. Gerar e validar isso cookie é executado pelo Cookie Middleware de Autenticação. O middleware serializa uma entidade de segurança de usuário em um criptografado cookie. Em solicitações subsequentes, o middleware valida o cookie, recria a entidade de segurança e atribui a entidade de segurança à HttpContext.User propriedade.

Autenticação baseada em token

Quando um usuário é autenticado, ele recebe um token (não um token antiforgery). O token contém informações do usuário na forma de declarações ou um token de referência que aponta o aplicativo para o estado do usuário mantido no aplicativo. Quando um usuário tenta acessar um recurso que requer autenticação, o token é enviado para o aplicativo com um cabeçalho de autorização extra na forma de um token portador. Essa abordagem torna o aplicativo sem estado. Em cada solicitação subsequente, o token é passado na solicitação de validação do lado do servidor. Esse token não é criptografado; está codificado. No servidor, o token é decodificado para acessar suas informações. Para enviar o token em solicitações subsequentes, armazene o token no armazenamento local do navegador. Não se preocupe com a vulnerabilidade CSRF se o token estiver armazenado no armazenamento local do navegador. CSRF é uma preocupação quando o token é armazenado em um cookie. Para obter mais informações, consulte o GitHub exemplo de código SPA de problema adiciona dois cookies.

Vários aplicativos hospedados em um domínio

Os ambientes de hospedagem compartilhada são vulneráveis ao sequestro de sessão, ao CSRF de logon e a outros ataques.

Embora example1.contoso.net e example2.contoso.net sejam hosts diferentes, há uma relação de confiança implícita entre hosts no *.contoso.net domínio. Essa relação de confiança implícita permite que hosts potencialmente não confiáveis afetem os dos outros cookie(as políticas de mesma origem que regem as solicitações AJAX não se aplicam necessariamente a HTTPs cookie).

Ataques que exploram s confiáveis cookieentre aplicativos hospedados no mesmo domínio podem ser evitados por não compartilhar domínios. Quando cada aplicativo é hospedado em seu próprio domínio, não há nenhuma relação de confiança implícita cookie a ser explorada.

Antiforgeria em ASP.NET Core

Aviso

ASP.NET Core implementa a antiforgeria usando ASP.NET Core Proteção de Dados. A pilha de proteção de dados deve ser configurada para funcionar em um farm de servidores. Para obter mais informações, consulte Configurar a proteção de dados.

O middleware antiforgery é adicionado ao contêiner de injeção de dependência quando uma das seguintes APIs é chamada em Program.cs:

O FormTagHelper injeta tokens de antiforgeria em elementos de formulário HTML. A seguinte marcação em um Razor arquivo gera automaticamente tokens antiforgery:

<form method="post">
    <!-- ... -->
</form>

Da mesma forma, IHtmlHelper.BeginForm gera tokens antiforgeria por padrão se o método do formulário não for GET.

A geração automática de tokens antiforgeria para elementos de formulário HTML ocorre quando a <form> marca contém o method="post" atributo e qualquer um dos seguintes são verdadeiros:

  • O atributo de ação está vazio (action="").
  • O atributo de ação não é fornecido (<form method="post">).

A geração automática de tokens antiforgeria para elementos de formulário HTML pode ser desabilitada:

  • Desabilite explicitamente tokens antiforgery com o asp-antiforgery atributo:

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • O elemento form é opted-out de Auxiliares de Marca usando o símbolo auxiliar de marca ! opt-out:

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Remova o FormTagHelper modo de exibição. O FormTagHelper modo de exibição pode ser removido adicionando a seguinte diretiva ao modo de exibição Razor :

    @removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
    

Observação

Razor As páginas são protegidas automaticamente contra XSRF/CSRF. Para obter mais informações, consulte XSRF/CSRF e Razor Pages.

A abordagem mais comum para se defender contra ataques CSRF é usar o Padrão de Token do Sincronizador (STP). O STP é usado quando o usuário solicita uma página com dados de formulário:

  1. O servidor envia um token associado à identidade do usuário atual para o cliente.
  2. O cliente envia de volta o token para o servidor para verificação.
  3. Se o servidor receber um token que não corresponda à identidade do usuário autenticado, a solicitação será rejeitada.

O token é exclusivo e imprevisível. O token também pode ser usado para garantir o sequenciamento adequado de uma série de solicitações (por exemplo, garantindo a sequência de solicitações de: página 1 > página 2 > página 3). Todos os formulários em ASP.NET Core modelos MVC e Razor Pages geram tokens antiforgeria. O seguinte par de exemplos de exibição gera tokens antiforgery:

<form asp-action="Index" asp-controller="Home" method="post">
    <!-- ... -->
</form>

@using (Html.BeginForm("Index", "Home"))
{
    <!-- ... -->
}

Adicione explicitamente um token antiforgery a um <form> elemento sem usar auxiliares de marca com o auxiliar @Html.AntiForgeryTokenHTML:

<form asp-action="Index" asp-controller="Home" method="post">
    @Html.AntiForgeryToken()

    <!-- ... -->
</form>

Em cada um dos casos anteriores, ASP.NET Core adiciona um campo de formulário oculto semelhante ao seguinte exemplo:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">

ASP.NET Core inclui três filtros para trabalhar com tokens antiforgeria:

Antiforgeria com AddControllers

A chamada AddControllersnão habilita tokens antiforgery. AddControllersWithViews deve ser chamado para ter suporte interno ao token antiforgery.

Várias guias do navegador e o padrão de token do sincronizador

Com o Padrão de Token do Sincronizador, apenas a página carregada mais recentemente contém um token antiforgery válido. O uso de várias guias pode ser problemático. Por exemplo, se um usuário abrir várias guias:

  • Somente a guia carregada mais recentemente contém um token antiforgery válido.
  • As solicitações feitas de guias carregadas anteriormente falham com um erro: Antiforgery token validation failed. The antiforgery cookie token and request token do not match

Considere padrões alternativos de proteção CSRF se isso representar um problema.

Configurar antiforgeria com AntiforgeryOptions

Personalizar AntiforgeryOptions em Program.cs:

builder.Services.AddAntiforgery(options =>
{
    // Set Cookie properties using CookieBuilder properties†.
    options.FormFieldName = "AntiforgeryFieldname";
    options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
    options.SuppressXFrameOptionsHeader = false;
});

Defina as propriedades antiforgeria Cookie usando as propriedades da CookieBuilder classe, conforme mostrado na tabela a seguir.

Opção Descrição
Cookie Determina as configurações usadas para criar os antiforgery cookies.
FormFieldName O nome do campo de formulário oculto usado pelo sistema antiforgery para renderizar tokens antiforgeria em exibições.
HeaderName O nome do cabeçalho usado pelo sistema antiforgery. Se null, o sistema considerará apenas os dados do formulário.
SuppressXFrameOptionsHeader Especifica se a geração do X-Frame-Options cabeçalho deve ser suprimida. Por padrão, o cabeçalho é gerado com um valor de "SAMEORIGIN". Assume o padrão de false.

Para obter mais informações, consulte CookieAuthenticationOptions.

Gerar tokens antiforgery com IAntiforgery

IAntiforgery fornece a API para configurar recursos antiforgeria. IAntiforgery pode ser solicitado ao Program.cs usar WebApplication.Services. O exemplo a seguir usa o middleware da home page do aplicativo para gerar um token antiforgery e enviá-lo na resposta como um cookie:

app.UseRouting();

app.UseAuthorization();

var antiforgery = app.Services.GetRequiredService<IAntiforgery>();

app.Use((context, next) =>
{
    var requestPath = context.Request.Path.Value;

    if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
        || string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
    {
        var tokenSet = antiforgery.GetAndStoreTokens(context);
        context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
            new CookieOptions { HttpOnly = false });
    }

    return next(context);
});

O exemplo anterior define um cookie nome XSRF-TOKEN. O cliente pode ler isso cookie e fornecer seu valor como um cabeçalho anexado às solicitações do AJAX. Por exemplo, Angular inclui proteção XSRF interna que lê um cookie nomeado XSRF-TOKEN por padrão.

Exigir validação antiforgeria

O filtro de ação ValidateAntiForgeryToken pode ser aplicado a uma ação individual, a um controlador ou globalmente. As solicitações feitas às ações que têm esse filtro aplicado são bloqueadas, a menos que a solicitação inclua um token antiforgery válido:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
    // ...

    return RedirectToAction();
}

O ValidateAntiForgeryToken atributo requer um token para solicitações aos métodos de ação que ele marca, incluindo solicitações HTTP GET. Se o ValidateAntiForgeryToken atributo for aplicado entre os controladores do aplicativo, ele poderá ser substituído com o IgnoreAntiforgeryToken atributo.

Validar automaticamente tokens antiforgery somente para métodos HTTP não seguros

Em vez de aplicar amplamente o ValidateAntiForgeryToken atributo e substituí-lo com IgnoreAntiforgeryToken atributos, o atributo AutoValidateAntiforgeryToken pode ser usado. Esse atributo funciona de forma idêntica ao ValidateAntiForgeryToken atributo, exceto por não exigir tokens para solicitações feitas usando os seguintes métodos HTTP:

  • GET
  • HEAD
  • OPÇÕES
  • RASTREAMENTO

É recomendável usar amplamente AutoValidateAntiforgeryToken para cenários que não são de API. Esse atributo garante que as ações POST sejam protegidas por padrão. A alternativa é ignorar tokens antiforgeria por padrão, a menos que seja aplicado a métodos ValidateAntiForgeryToken de ação individuais. É mais provável neste cenário que um método de ação POST seja deixado desprotegido por engano, deixando o aplicativo vulnerável a ataques CSRF. Todos os POSTs devem enviar o token antiforgery.

As APIs não têm um mecanismo automático para enviar a não partecookie do token. A implementação provavelmente depende da implementação do código do cliente. Alguns exemplos são mostrados abaixo:

Exemplo de nível de classe:

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Exemplo global:

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});

Substituir atributos de antiforgeria global ou controlador

O filtro IgnoreAntiforgeryToken é usado para eliminar a necessidade de um token antiforgery para uma determinada ação (ou controlador). Quando aplicado, esse filtro substitui ValidateAntiForgeryToken e AutoValidateAntiforgeryToken filtra especificados em um nível mais alto (globalmente ou em um controlador).

[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
    // ...

    return RedirectToAction();
}

Atualizar tokens após a autenticação

Os tokens devem ser atualizados depois que o usuário for autenticado redirecionando o usuário para uma exibição ou Razor página Páginas.

JavaScript, AJAX e SPAs

Em aplicativos tradicionais baseados em HTML, tokens antiforgeria são passados para o servidor usando campos de formulário ocultos. Em aplicativos modernos baseados em JavaScript e SPAs, muitas solicitações são feitas programaticamente. Essas solicitações AJAX podem usar outras técnicas (como cabeçalhos de solicitação ou cookies) para enviar o token.

Se cookies forem usados para armazenar tokens de autenticação e autenticar solicitações de API no servidor, o CSRF será um problema em potencial. Se o armazenamento local for usado para armazenar o token, a vulnerabilidade CSRF poderá ser atenuada porque os valores do armazenamento local não são enviados automaticamente para o servidor a cada solicitação. Usar o armazenamento local para armazenar o token antiforgery no cliente e enviar o token como cabeçalho de solicitação é uma abordagem recomendada.

JavaScript

Usando JavaScript com exibições, o token pode ser criado usando um serviço de dentro da exibição. Injete o IAntiforgery serviço na exibição e chame GetAndStoreTokens:

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery

@{
    ViewData["Title"] = "JavaScript";

    var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}

<input id="RequestVerificationToken" type="hidden" value="@requestToken" />

<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>

@section Scripts {
<script>
    document.addEventListener("DOMContentLoaded", () => {
        const resultElement = document.getElementById("result");

        document.getElementById("button").addEventListener("click", async () => {

            const response = await fetch("@Url.Action("FetchEndpoint")", {
                method: "POST",
                headers: {
                    RequestVerificationToken:
                        document.getElementById("RequestVerificationToken").value
                }
            });

            if (response.ok) {
                resultElement.innerText = await response.text();
            } else {
                resultElement.innerText = `Request Failed: ${response.status}`
            }
        });
    });
</script>
}

Essa abordagem elimina a necessidade de lidar diretamente com as configurações cookiedo servidor ou lê-las do cliente.

O exemplo anterior usa JavaScript para ler o valor do campo oculto para o cabeçalho POST do AJAX.

O JavaScript também pode acessar tokens em cookies e usar o cookieconteúdo para criar um cabeçalho com o valor do token. O exemplo a seguir grava o token de solicitação em um JavaScript legível cookie:

context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
    new CookieOptions { HttpOnly = false });

Supondo que o script envie o token em um cabeçalho de solicitação chamado X-XSRF-TOKEN, configure o serviço antiforgery para procurar o X-XSRF-TOKEN cabeçalho:

builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");

O exemplo a seguir usa JavaScript para fazer uma solicitação AJAX com o cabeçalho apropriado:

// https://developer.mozilla.org/en-US/docs/web/api/document/cookie
const xsrfToken = document.cookie
    .split("; ")
    .find(row => row.startsWith("XSRF-TOKEN="))
    .split("=")[1];

const response = await fetch("/JavaScript/FetchEndpoint", {
    method: "POST",
    headers: { "X-XSRF-TOKEN": xsrfToken }
});

if (response.ok) {
    resultElement.innerText = await response.text();
} else {
    resultElement.innerText = `Request Failed: ${response.status}`
}

autenticação do Windows e antiforgeria cookies

Ao usar Windows Autenticação, os pontos de extremidade do aplicativo devem ser protegidos contra ataques CSRF da mesma forma que feito para cookies. O navegador envia implicitamente o contexto de autenticação para o servidor e, portanto, os pontos de extremidade precisam ser protegidos contra ataques CSRF.

Estender antiforgeria

O IAntiforgeryAdditionalDataProvider tipo permite que os desenvolvedores estendam o comportamento do sistema anti-CSRF, arredondando dados adicionais em cada token. O GetAdditionalData método é chamado sempre que um token de campo é gerado e o valor retornado é inserido no token gerado. Um implementador pode retornar um carimbo de data/hora, um nonce ou qualquer outro valor e, em seguida, chamar ValidateAdditionalData para validar esses dados quando o token for validado. O nome de usuário do cliente já está inserido nos tokens gerados, portanto, não é necessário incluir essas informações. Se um token incluir dados suplementares, mas não IAntiForgeryAdditionalDataProvider estiver configurado, os dados complementares não serão validados.

Recursos adicionais

A falsificação de solicitação entre sites (também conhecida como XSRF ou CSRF) é um ataque contra aplicativos hospedados na Web em que um aplicativo Web mal-intencionado pode influenciar a interação entre um navegador cliente e um aplicativo Web que confia nesse navegador. Esses ataques são possíveis porque os navegadores da Web enviam alguns tipos de tokens de autenticação automaticamente com cada solicitação para um site. Essa forma de exploração também é conhecida como um ataque de um clique ou uma corrida de sessão porque o ataque aproveita a sessão autenticada anteriormente do usuário.

Um exemplo de um ataque CSRF:

  1. Um usuário entra usando www.good-banking-site.com a autenticação de formulários. O servidor autentica o usuário e emite uma resposta que inclui uma autenticação cookie. O site está vulnerável a ataques porque confia em qualquer solicitação recebida com uma autenticação cookieválida.

  2. O usuário visita um site mal-intencionado. www.bad-crook-site.com

    O site www.bad-crook-site.commal-intencionado contém um formulário HTML semelhante ao seguinte exemplo:

    <h1>Congratulations! You're a Winner!</h1>
    <form action="https://good-banking-site.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

    Observe que as postagens do action formulário para o site vulnerável, não para o site mal-intencionado. Essa é a parte "entre sites" do CSRF.

  3. O usuário seleciona o botão Enviar. O navegador faz a solicitação e inclui automaticamente a autenticação cookie para o domínio solicitado. www.good-banking-site.com

  4. A solicitação é executada no www.good-banking-site.com servidor com o contexto de autenticação do usuário e pode executar qualquer ação que um usuário autenticado tenha permissão para executar.

Além do cenário em que o usuário seleciona o botão para enviar o formulário, o site mal-intencionado pode:

  • Execute um script que envia automaticamente o formulário.
  • Envie o envio do formulário como uma solicitação AJAX.
  • Oculte o formulário usando CSS.

Esses cenários alternativos não exigem nenhuma ação ou entrada do usuário além de visitar inicialmente o site mal-intencionado.

O uso de HTTPS não impede um ataque CSRF. O site mal-intencionado pode enviar uma solicitação https://www.good-banking-site.com/ tão facilmente quanto pode enviar uma solicitação insegura.

Alguns ataques têm como alvo pontos de extremidade que respondem a solicitações GET, nesse caso, uma marca de imagem pode ser usada para executar a ação. Essa forma de ataque é comum em sites de fórum que permitem imagens, mas bloqueiam JavaScript. Os aplicativos que alteram o estado em solicitações GET, em que variáveis ou recursos são alterados, são vulneráveis a ataques mal-intencionados. Solicitações GET que alteram o estado são inseguras. Uma prática recomendada é nunca alterar o estado em uma solicitação GET.

Ataques CSRF são possíveis em aplicativos Web que usam cookies para autenticação porque:

  • Repositórios cookiede navegadores emitidos por um aplicativo Web.
  • Os armazenamentos cookieincluem sessões cookiepara usuários autenticados.
  • Os navegadores enviam todos os cookies associados a um domínio para o aplicativo Web a cada solicitação, independentemente de como a solicitação para o aplicativo foi gerada dentro do navegador.

No entanto, os ataques CSRF não se limitam à exploração cookiede s. Por exemplo, a autenticação Básica e Digest também é vulnerável. Depois que um usuário entra com a autenticação Básica ou Digest, o navegador envia automaticamente as credenciais até que a sessão termine.

Nesse contexto, a sessão refere-se à sessão do lado do cliente durante a qual o usuário é autenticado. Não está relacionado a sessões do lado do servidor ou ASP.NET Core Middleware de Sessão.

Os usuários podem se proteger contra vulnerabilidades CSRF tomando precauções:

  • Saia de aplicativos Web quando terminar de usá-los.
  • Limpe o navegador cookieperiodicamente.

No entanto, as vulnerabilidades CSRF são fundamentalmente um problema com o aplicativo Web, não com o usuário final.

Conceitos básicos sobre autenticação

CookieA autenticação baseada é uma forma popular de autenticação. Os sistemas de autenticação baseados em token estão crescendo em popularidade, especialmente para SPAs (Aplicativos de Página Única).

Quando um usuário autentica usando seu nome de usuário e senha, ele é emitido um token, contendo um tíquete de autenticação que pode ser usado para autenticação e autorização. O token é armazenado como um cookie que é enviado a cada solicitação que o cliente faz. Gerar e validar isso cookie é executado pelo Cookie Middleware de Autenticação. O middleware serializa uma entidade de segurança de usuário em um criptografado cookie. Em solicitações subsequentes, o middleware valida o cookie, recria a entidade de segurança e atribui a entidade de segurança à HttpContext.User propriedade.

Autenticação baseada em token

Quando um usuário é autenticado, ele recebe um token (não um token antiforgery). O token contém informações do usuário na forma de declarações ou um token de referência que aponta o aplicativo para o estado do usuário mantido no aplicativo. Quando um usuário tenta acessar um recurso que requer autenticação, o token é enviado para o aplicativo com um cabeçalho de autorização extra na forma de um token portador. Essa abordagem torna o aplicativo sem estado. Em cada solicitação subsequente, o token é passado na solicitação de validação do lado do servidor. Esse token não é criptografado; está codificado. No servidor, o token é decodificado para acessar suas informações. Para enviar o token em solicitações subsequentes, armazene o token no armazenamento local do navegador. Não se preocupe com a vulnerabilidade CSRF se o token estiver armazenado no armazenamento local do navegador. CSRF é uma preocupação quando o token é armazenado em um cookie. Para obter mais informações, consulte o GitHub exemplo de código SPA de problema adiciona dois cookies.

Vários aplicativos hospedados em um domínio

Os ambientes de hospedagem compartilhada são vulneráveis ao sequestro de sessão, ao CSRF de logon e a outros ataques.

Embora example1.contoso.net e example2.contoso.net sejam hosts diferentes, há uma relação de confiança implícita entre hosts no *.contoso.net domínio. Essa relação de confiança implícita permite que hosts potencialmente não confiáveis afetem os dos outros cookie(as políticas de mesma origem que regem as solicitações AJAX não se aplicam necessariamente a HTTPs cookie).

Ataques que exploram s confiáveis cookieentre aplicativos hospedados no mesmo domínio podem ser evitados por não compartilhar domínios. Quando cada aplicativo é hospedado em seu próprio domínio, não há nenhuma relação de confiança implícita cookie a ser explorada.

ASP.NET Core configuração antiforgeria

Aviso

ASP.NET Core implementa a antiforgeria usando ASP.NET Core Proteção de Dados. A pilha de proteção de dados deve ser configurada para funcionar em um farm de servidores. Para obter mais informações, consulte Configurar a proteção de dados.

O middleware antiforgery é adicionado ao contêiner de injeção de dependência quando uma das seguintes APIs é chamada em Startup.ConfigureServices:

No ASP.NET Core 2.0 ou posterior, o FormTagHelper injeta tokens de antiforgeria em elementos de formulário HTML. A seguinte marcação em um Razor arquivo gera automaticamente tokens antiforgery:

<form method="post">
    ...
</form>

Da mesma forma, IHtmlHelper.BeginForm gera tokens antiforgeria por padrão se o método do formulário não for GET.

A geração automática de tokens antiforgeria para elementos de formulário HTML ocorre quando a <form> marca contém o method="post" atributo e qualquer um dos seguintes são verdadeiros:

  • O atributo de ação está vazio (action="").
  • O atributo de ação não é fornecido (<form method="post">).

A geração automática de tokens antiforgeria para elementos de formulário HTML pode ser desabilitada:

  • Desabilite explicitamente tokens antiforgery com o asp-antiforgery atributo:

    <form method="post" asp-antiforgery="false">
        ...
    </form>
    
  • O elemento form é opted-out de Auxiliares de Marca usando o símbolo auxiliar de marca ! opt-out:

    <!form method="post">
        ...
    </!form>
    
  • Remova o FormTagHelper modo de exibição. O FormTagHelper modo de exibição pode ser removido adicionando a seguinte diretiva ao modo de exibição Razor :

    @removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
    

Observação

Razor As páginas são protegidas automaticamente contra XSRF/CSRF. Para obter mais informações, consulte XSRF/CSRF e Razor Pages.

A abordagem mais comum para se defender contra ataques CSRF é usar o Padrão de Token do Sincronizador (STP). O STP é usado quando o usuário solicita uma página com dados de formulário:

  1. O servidor envia um token associado à identidade do usuário atual para o cliente.
  2. O cliente envia de volta o token para o servidor para verificação.
  3. Se o servidor receber um token que não corresponda à identidade do usuário autenticado, a solicitação será rejeitada.

O token é exclusivo e imprevisível. O token também pode ser usado para garantir o sequenciamento adequado de uma série de solicitações (por exemplo, garantindo a sequência de solicitações de: página 1 > página 2 > página 3). Todos os formulários em ASP.NET Core modelos MVC e Razor Pages geram tokens antiforgeria. O seguinte par de exemplos de exibição gera tokens antiforgery:

<form asp-controller="Todo" asp-action="Create" method="post">
    ...
</form>

@using (Html.BeginForm("Create", "Todo"))
{
    ...
}

Adicione explicitamente um token antiforgery a um <form> elemento sem usar auxiliares de marca com o auxiliar @Html.AntiForgeryTokenHTML:

<form action="/" method="post">
    @Html.AntiForgeryToken()
</form>

Em cada um dos casos anteriores, ASP.NET Core adiciona um campo de formulário oculto semelhante ao seguinte exemplo:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">

ASP.NET Core inclui três filtros para trabalhar com tokens antiforgeria:

Opções de antiforgeria

Personalizar AntiforgeryOptions em Startup.ConfigureServices:

services.AddAntiforgery(options => 
{
    options.FormFieldName = "AntiforgeryFieldname";
    options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
    options.SuppressXFrameOptionsHeader = false;
});

Defina as propriedades antiforgeria Cookie usando as propriedades da CookieBuilder classe, conforme mostrado na tabela a seguir.

Opção Descrição
Cookie Determina as configurações usadas para criar os antiforgery cookies.
FormFieldName O nome do campo de formulário oculto usado pelo sistema antiforgery para renderizar tokens antiforgeria em exibições.
HeaderName O nome do cabeçalho usado pelo sistema antiforgery. Se null, o sistema considerará apenas os dados do formulário.
SuppressXFrameOptionsHeader Especifica se a geração do X-Frame-Options cabeçalho deve ser suprimida. Por padrão, o cabeçalho é gerado com um valor de "SAMEORIGIN". Assume o padrão de false.

Para obter mais informações, consulte CookieAuthenticationOptions.

Configurar recursos de antiforgeria com IAntiforgery

IAntiforgery fornece a API para configurar recursos antiforgeria. IAntiforgery pode ser solicitado no Configure método da Startup classe.

No exemplo a seguir:

  • O middleware da home page do aplicativo é usado para gerar um token antiforgery e enviá-lo na resposta como um cookie.
  • O token de solicitação é enviado como um JavaScript legível cookie com a convenção de nomenclatura padrão Angular descrita na seção AngularJS.
public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
    app.Use(next => context =>
    {
        string path = context.Request.Path.Value;

        if (string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
            string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
        {
            var tokens = antiforgery.GetAndStoreTokens(context);
            context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, 
                new CookieOptions() { HttpOnly = false });
        }

        return next(context);
    });
}

Exigir validação antiforgeria

ValidateAntiForgeryToken é um filtro de ação que pode ser aplicado a uma ação individual, a um controlador ou globalmente. As solicitações feitas às ações que têm esse filtro aplicado são bloqueadas, a menos que a solicitação inclua um token antiforgery válido.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> RemoveLogin(RemoveLoginViewModel account)
{
    ManageMessageId? message = ManageMessageId.Error;
    var user = await GetCurrentUserAsync();

    if (user != null)
    {
        var result = 
            await _userManager.RemoveLoginAsync(
                user, account.LoginProvider, account.ProviderKey);

        if (result.Succeeded)
        {
            await _signInManager.SignInAsync(user, isPersistent: false);
            message = ManageMessageId.RemoveLoginSuccess;
        }
    }

    return RedirectToAction(nameof(ManageLogins), new { Message = message });
}

O ValidateAntiForgeryToken atributo requer um token para solicitações aos métodos de ação que ele marca, incluindo solicitações HTTP GET. Se o ValidateAntiForgeryToken atributo for aplicado entre os controladores do aplicativo, ele poderá ser substituído com o IgnoreAntiforgeryToken atributo.

Observação

ASP.NET Core não dá suporte à adição de tokens antiforgeria às solicitações GET automaticamente.

Validar automaticamente tokens antiforgery somente para métodos HTTP não seguros

ASP.NET Core aplicativos não geram tokens antiforgery para métodos HTTP seguros (GET, HEAD, OPTIONS e TRACE). Em vez de aplicar amplamente o ValidateAntiForgeryToken atributo e substituí-lo com IgnoreAntiforgeryToken atributos, o atributo AutoValidateAntiforgeryToken pode ser usado. Esse atributo funciona de forma idêntica ao ValidateAntiForgeryToken atributo, exceto por não exigir tokens para solicitações feitas usando os seguintes métodos HTTP:

  • GET
  • HEAD
  • OPÇÕES
  • RASTREAMENTO

É recomendável usar amplamente AutoValidateAntiforgeryToken para cenários que não são de API. Esse atributo garante que as ações POST sejam protegidas por padrão. A alternativa é ignorar tokens antiforgeria por padrão, a menos que seja aplicado a métodos ValidateAntiForgeryToken de ação individuais. É mais provável neste cenário que um método de ação POST seja deixado desprotegido por engano, deixando o aplicativo vulnerável a ataques CSRF. Todos os POSTs devem enviar o token antiforgery.

As APIs não têm um mecanismo automático para enviar a não partecookie do token. A implementação provavelmente depende da implementação do código do cliente. Alguns exemplos são mostrados abaixo:

Exemplo de nível de classe:

[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{

Exemplo global:

services.AddControllersWithViews(options =>
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));

Substituir atributos de antiforgeria global ou controlador

O filtro IgnoreAntiforgeryToken é usado para eliminar a necessidade de um token antiforgery para uma determinada ação (ou controlador). Quando aplicado, esse filtro substitui ValidateAntiForgeryToken e AutoValidateAntiforgeryToken filtra especificados em um nível mais alto (globalmente ou em um controlador).

[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{
    [HttpPost]
    [IgnoreAntiforgeryToken]
    public async Task<IActionResult> DoSomethingSafe(SomeViewModel model)
    {
        // no antiforgery token required
    }
}

Atualizar tokens após a autenticação

Os tokens devem ser atualizados depois que o usuário for autenticado redirecionando o usuário para uma exibição ou Razor página Páginas.

JavaScript, AJAX e SPAs

Em aplicativos tradicionais baseados em HTML, tokens antiforgeria são passados para o servidor usando campos de formulário ocultos. Em aplicativos modernos baseados em JavaScript e SPAs, muitas solicitações são feitas programaticamente. Essas solicitações AJAX podem usar outras técnicas (como cabeçalhos de solicitação ou cookies) para enviar o token.

Se cookies forem usados para armazenar tokens de autenticação e autenticar solicitações de API no servidor, o CSRF será um problema em potencial. Se o armazenamento local for usado para armazenar o token, a vulnerabilidade CSRF poderá ser atenuada porque os valores do armazenamento local não são enviados automaticamente para o servidor a cada solicitação. Usar o armazenamento local para armazenar o token antiforgery no cliente e enviar o token como cabeçalho de solicitação é uma abordagem recomendada.

JavaScript

Usando JavaScript com exibições, o token pode ser criado usando um serviço de dentro da exibição. Injete o IAntiforgery serviço na exibição e chame GetAndStoreTokens:

@{
    ViewData["Title"] = "AJAX Demo";
}
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
    public string GetAntiXsrfRequestToken()
    {
        return Xsrf.GetAndStoreTokens(Context).RequestToken;
    }
}

<input type="hidden" id="RequestVerificationToken" 
       name="RequestVerificationToken" value="@GetAntiXsrfRequestToken()">

<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>

<div class="row">
    <p><input type="button" id="antiforgery" value="Antiforgery"></p>
    <script>
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (xhttp.readyState == XMLHttpRequest.DONE) {
                if (xhttp.status == 200) {
                    alert(xhttp.responseText);
                } else {
                    alert('There was an error processing the AJAX request.');
                }
            }
        };

        document.addEventListener('DOMContentLoaded', function() {
            document.getElementById("antiforgery").onclick = function () {
                xhttp.open('POST', '@Url.Action("Antiforgery", "Home")', true);
                xhttp.setRequestHeader("RequestVerificationToken", 
                    document.getElementById('RequestVerificationToken').value);
                xhttp.send();
            }
        });
    </script>
</div>

Essa abordagem elimina a necessidade de lidar diretamente com as configurações cookiedo servidor ou lê-las do cliente.

O exemplo anterior usa JavaScript para ler o valor do campo oculto para o cabeçalho POST do AJAX.

O JavaScript também pode acessar tokens em cookies e usar o cookieconteúdo para criar um cabeçalho com o valor do token.

context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken, 
    new Microsoft.AspNetCore.Http.CookieOptions { HttpOnly = false });

Supondo que o script solicite o envio do token em um cabeçalho chamado X-CSRF-TOKEN, configure o serviço antiforgery para procurar o X-CSRF-TOKEN cabeçalho:

services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN");

O exemplo a seguir usa JavaScript para fazer uma solicitação AJAX com o cabeçalho apropriado:

function getCookie(cname) {
    var name = cname + "=";
    var decodedCookie = decodeURIComponent(document.cookie);
    var ca = decodedCookie.split(';');
    for (var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) === ' ') {
            c = c.substring(1);
        }
        if (c.indexOf(name) === 0) {
            return c.substring(name.length, c.length);
        }
    }
    return "";
}

var csrfToken = getCookie("CSRF-TOKEN");

var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
    if (xhttp.readyState === XMLHttpRequest.DONE) {
        if (xhttp.status === 204) {
            alert('Todo item is created successfully.');
        } else {
            alert('There was an error processing the AJAX request.');
        }
    }
};
xhttp.open('POST', '/api/items', true);
xhttp.setRequestHeader("Content-type", "application/json");
xhttp.setRequestHeader("X-CSRF-TOKEN", csrfToken);
xhttp.send(JSON.stringify({ "name": "Learn C#" }));

AngularJS

O AngularJS usa uma convenção para tratar do CSRF. Se o servidor enviar um cookie com o nome XSRF-TOKEN, o serviço AngularJS $http adicionará o cookie valor a um cabeçalho quando enviar uma solicitação ao servidor. Esse processo é automático. O cliente não precisa definir o cabeçalho explicitamente. O nome do cabeçalho é X-XSRF-TOKEN. O servidor deve detectar esse cabeçalho e validar seu conteúdo.

Para que ASP.NET Core API funcione com essa convenção na inicialização do aplicativo:

  • Configure seu aplicativo para fornecer um token em um cookie chamado XSRF-TOKEN.
  • Configure o serviço antiforgery para procurar um cabeçalho nomeadoX-XSRF-TOKEN, que é o nome de cabeçalho padrão do Angular para enviar o token XSRF.
public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
    app.Use(next => context =>
    {
        string path = context.Request.Path.Value;

        if (
            string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
            string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
        {
            var tokens = antiforgery.GetAndStoreTokens(context);
            context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, 
                new CookieOptions() { HttpOnly = false });
        }

        return next(context);
    });
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
}

autenticação do Windows e antiforgeria cookies

Ao usar Windows Autenticação, os pontos de extremidade do aplicativo devem ser protegidos contra ataques CSRF da mesma forma que feito para cookies. O navegador envia implicitamente o contexto de autenticação para o servidor e, portanto, os pontos de extremidade precisam ser protegidos contra ataques CSRF.

Estender antiforgeria

O IAntiforgeryAdditionalDataProvider tipo permite que os desenvolvedores estendam o comportamento do sistema anti-CSRF, arredondando dados adicionais em cada token. O GetAdditionalData método é chamado sempre que um token de campo é gerado e o valor retornado é inserido no token gerado. Um implementador pode retornar um carimbo de data/hora, um nonce ou qualquer outro valor e, em seguida, chamar ValidateAdditionalData para validar esses dados quando o token for validado. O nome de usuário do cliente já está inserido nos tokens gerados, portanto, não é necessário incluir essas informações. Se um token incluir dados suplementares, mas não IAntiForgeryAdditionalDataProvider estiver configurado, os dados complementares não serão validados.

Recursos adicionais