Previna ataques de falsificação de solicitação entre sites (XSRF/CSRF) no ASP.NET Core
Por Fiyaz Hasan e Rick Anderson
A falsificação de solicitação entre sites é um ataque contra aplicativos hospedados na Web pelo qual 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 a cada solicitação para um site. Essa forma de exploração também é conhecida como ataque de um clique ou sequestro de sessão porque o ataque aproveita a sessão previamente autenticada do utilizador. A falsificação de solicitação entre sites também é conhecida como XSRF ou CSRF.
Um exemplo de um ataque CSRF:
Um utilizador entra em
www.good-banking-site.example.com
usando a autenticação por formulários. O servidor autentica o usuário e emite uma resposta que inclui uma autenticação cookie. O site é vulnerável a ataques porque confia em qualquer solicitação recebida com uma autenticação válida cookie.O utilizador visita um site malicioso,
www.bad-crook-site.example.com
.O site mal-intencionado,
www.bad-crook-site.example.com
, contém um formulário HTML semelhante ao exemplo a seguir:<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 o
action
do formulário envia informações para o site vulnerável, não para o site malicioso. Esta é a parte "cross-site" da CSRF.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.example.com
.A solicitação é executada no servidor
www.good-banking-site.example.com
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 de https://www.good-banking-site.com/
tão facilmente quanto pode enviar uma solicitação insegura.
Alguns ataques têm como alvo endpoints que respondem a solicitações GET, caso em que uma etiqueta de imagem pode ser usada para executar a ação. Esta forma de ataque é comum em sites de fóruns que permitem imagens, mas bloqueiam JavaScript. Os aplicativos que mudam de estado em solicitações GET, onde variáveis ou recursos são alterados, são vulneráveis a ataques mal-intencionados. As solicitações GET que mudam de estado são inseguras. Uma prática recomendada é nunca alterar o estado em uma solicitação GET.
Os ataques CSRF são possíveis contra aplicativos da Web que usam cookies para autenticação porque:
- Os navegadores armazenam cookies emitidos por um aplicativo da Web.
- Os cookies armazenados incluem cookies de sessão para utilizadores 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 de cookies. Por exemplo, as autenticações Basic e Digest também são vulneráveis. Depois que um usuário entra com autenticação Básica ou Digest, o navegador envia automaticamente as credenciais até que a sessão termine.
Neste contexto, sessão refere-se à sessão do lado do cliente durante a qual o usuário é autenticado. Não está relacionado com sessões do lado do servidor ou ASP.NET Core Session Middleware.
Os usuários podem se proteger contra vulnerabilidades CSRF tomando precauções:
- Saia dos aplicativos Web quando terminar de usá-los.
- Limpe os cookies do navegador periodicamente.
No entanto, as vulnerabilidades CSRF são fundamentalmente um problema com o aplicativo Web, não com o usuário final.
Fundamentos de autenticação
A autenticação baseada em Cookieé uma forma popular de autenticação. Os sistemas de autenticação baseados em tokens estão crescendo em popularidade, especialmente para aplicativos de página única (SPAs).
Autenticação baseada em Cookie
Quando um usuário se autentica usando seu nome de usuário e senha, ele recebe um token contendo um tíquete de autenticação. O token pode ser usado para autenticação e autorização. O token é armazenado como um cookie que é enviado a cada solicitação feita pelo cliente. A geração e validação desse cookie é realizada com o middleware de autenticação Cookie. O middleware serializa uma entidade de usuário em um cookiecriptografado. Em solicitações subsequentes, o middleware valida o cookie, recria o principal e atribui o principal à propriedade HttpContext.User.
Autenticação baseada em tokens
Quando um usuário é autenticado, ele recebe um token (não um token antifalsificação). 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 de portador. Essa abordagem torna a aplicação sem estado. Em cada solicitação subsequente, o token é passado na solicitação de validação do lado do servidor. Este token não é criptografado; é codificado. No servidor, o token é decodificado para acessar suas informações. Para enviar o token em solicitações subsequentes, armazene-o no armazenamento local do navegador. Colocar um token no armazenamento local do navegador e recuperá-lo e usá-lo como um token de portador fornece proteção contra ataques CSRF. No entanto, se o aplicativo estiver vulnerável à injeção de script via XSS ou a um arquivo JavaScript externo comprometido, um ciberinvasor poderá recuperar qualquer valor do armazenamento local e enviá-lo para si mesmo. ASP.NET Core codifica todas as saídas do lado do servidor de variáveis por padrão, reduzindo o risco de XSS. Se você substituir esse comportamento usando Html.Raw ou código personalizado com entrada não confiável, então você pode aumentar o risco de XSS.
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 num cookie. Para obter mais informações, consulte o problema da GitHub , onde o exemplo de código SPA adiciona dois cookies.
Vários aplicativos hospedados em um domínio
Os ambientes de alojamento partilhado são vulneráveis a sequestro de sessão, CSRF no início de sessão e outros ataques.
Embora example1.contoso.net
e example2.contoso.net
sejam hosts diferentes, há uma relação de confiança implícita entre hosts sob o domínio *.contoso.net
. Essa relação de confiança implícita permite que hosts potencialmente não confiáveis afetem os cookies uns dos outros (as políticas de mesma origem que regem as solicitações AJAX não se aplicam necessariamente aos cookies HTTP).
Os ataques que exploram cookies confiáveis entre aplicativos hospedados no mesmo domínio podem ser evitados não compartilhando domínios. Quando cada aplicativo é hospedado em seu próprio domínio, não há nenhuma relação de confiança implícita cookie para explorar.
Antifalsificação no ASP.NET Core
Advertência
ASP.NET Core implementa antifalsificação usando ASP.NET Core Data Protection. A pilha de proteção de dados deve ser configurada para funcionar numa server farm. Para obter mais informações, consulte Configurando a proteção de dados.
O middleware antifalsificação é adicionado ao contêiner de de injeção de dependência do
Para obter mais informações, consulte Antifalsificação com APIs Mínimas.
O FormTagHelper injeta tokens antifalsificação em elementos de formulário HTML. A marcação a seguir em um arquivo Razor gera automaticamente tokens antifalsificação:
<form method="post">
<!-- ... -->
</form>
Da mesma forma, IHtmlHelper.BeginForm gera tokens antifalsificação por padrão se o método do formulário não for GET.
A geração automática de tokens antifalsificação para elementos de formulário HTML acontece quando a tag <form>
contém o atributo method="post"
e uma das seguintes opções é verdadeira:
- O atributo action está vazio (
action=""
). - O atributo action não é fornecido (
<form method="post">
).
A geração automática de tokens antifalsificação para elementos de formulário HTML pode ser desativada:
Desative explicitamente os tokens antifalsificação com o atributo
asp-antiforgery
:<form method="post" asp-antiforgery="false"> <!-- ... --> </form>
O elemento de formulário é excluído dos Auxiliares de Tag usando o símbolo de exclusão do Auxiliar de Tag !:
<!form method="post"> <!-- ... --> </!form>
Remova o
FormTagHelper
da vista. OFormTagHelper
pode ser removido de um modo de exibição adicionando a seguinte diretiva ao modo de exibição Razor:@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Observação
Razor Páginas são automaticamente protegidas contra XSRF/CSRF. Para obter mais informações, consulte XSRF/CSRF e Razor Pages.
A abordagem mais comum para proteger contra ataques CSRF é usar o Synchronizer Token Pattern (STP). O STP é usado quando o usuário solicita uma página com dados de formulário:
- O servidor envia um token associado ao identity do usuário atual para o cliente.
- O cliente envia de volta o token para o servidor para verificação.
- Se o servidor receber um token que não corresponde ao identitydo usuário autenticado, a solicitação será rejeitada.
O token é único 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ção de: página 1 > página 2 > página 3). Todos os formulários nos modelos ASP.NET Core MVC e Razor Pages geram tokens antifalsificação. O seguinte par de exemplos de visualização gera tokens antifalsificação:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Adicione explicitamente um token antifalsificação a um elemento <form>
sem usar Tag Helpers com o HTML helper @Html.AntiForgeryToken
:
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
Em cada um dos casos anteriores, o ASP.NET Core adiciona um campo de formulário oculto semelhante ao exemplo a seguir:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core inclui três filtros para trabalhar com tokens antifalsificação:
Antifalsificação com AddControllers
Chamar AddControllersnão habilita tokens antifalsificação. AddControllersWithViews deve ser chamado para ter suporte de token antifalsificação integrado.
Várias guias do navegador e o Padrão de Token do Sincronizador
Com o Synchronizer Token Pattern, apenas a página carregada mais recentemente tem a garantia de conter um token antifalsificação válido. As aplicações que desejam suportar vários separadores devem testar os navegadores suportados e registar as falhas.
Usar várias guias pode ser problemático. Por exemplo, se um utilizador abrir várias guias, as solicitações feitas de guias já carregadas podem falhar 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 o antifalsificação com o AntiforgeryOptions
Personalize 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 antifalsificação Cookie
usando as propriedades da classe CookieBuilder, conforme mostrado na tabela a seguir.
Opção | Descrição |
---|---|
Cookie | Determina as configurações usadas para criar os cookies antifalsificação. |
FormFieldName | O nome do campo de formulário oculto usado pelo sistema antifalsificação para renderizar tokens antifalsificação em visualizações. |
HeaderName | O nome do cabeçalho usado pelo sistema antifalsificação. Se null , o sistema considera apenas os dados do formulário. |
SuppressXFrameOptionsHeader | Especifica se a geração do cabeçalho X-Frame-Options deve ser suprimida. Por padrão, o cabeçalho é gerado com um valor de "SAMEORIGIN". O padrão é false . |
Para obter mais informações, consulte CookieAuthenticationOptions.
Gere tokens antifalsificação com IAntiforgery
IAntiforgery fornece a API para configurar recursos antifalsificação.
IAntiforgery
pode ser solicitado em Program.cs
usando WebApplication.Services. O exemplo a seguir usa middleware da página de home do aplicativo para gerar um token anti-falsificação e incluí-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 chamado XSRF-TOKEN
. O cliente pode ler essa cookie e fornecer seu valor como um cabeçalho anexado às solicitações AJAX. Por exemplo, o Angular inclui proteção XSRF integrada que, por padrão, lê um cookie chamado XSRF-TOKEN
.
Exigir validação antifalsificação
O filtro de ação ValidateAntiForgeryToken pode ser aplicado a uma ação individual, a um controlador ou globalmente. As solicitações feitas para ações que têm esse filtro aplicado são bloqueadas, a menos que a solicitação inclua um token antifalsificação válido:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
O atributo ValidateAntiForgeryToken
requer um token para solicitações para os métodos de ação que ele marca, incluindo solicitações HTTP GET. Se o atributo ValidateAntiForgeryToken
for aplicado nos controladores do aplicativo, ele poderá ser substituído pelo atributo IgnoreAntiforgeryToken
.
Valide automaticamente tokens antifalsificação apenas para métodos HTTP inseguros
Em vez de aplicar amplamente o atributo ValidateAntiForgeryToken
e, em seguida, substituí-lo por IgnoreAntiforgeryToken
atributos, o AutoValidateAntiforgeryToken atributo pode ser usado. Esse atributo funciona de forma idêntica ao atributo ValidateAntiForgeryToken
, exceto que ele não requer tokens para solicitações feitas usando os seguintes métodos HTTP:
- OBTER
- CABEÇA
- OPÇÕES
- RASTREIO
Recomendamos o uso de AutoValidateAntiforgeryToken
de forma ampla para cenários que não sejam de API. Esse atributo garante que as ações POST sejam protegidas por padrão. A alternativa é ignorar tokens antifalsificação por padrão, a menos que ValidateAntiForgeryToken
seja aplicado a métodos 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 antifalsificação.
As APIs não têm um mecanismo automático para enviar a parte nãocookie 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 antifalsificação globais ou de controlador
O filtro IgnoreAntiforgeryToken é usado para eliminar a necessidade de um token antifalsificação para uma determinada ação (ou controlador). Quando aplicado, este filtro substitui os filtros ValidateAntiForgeryToken
e AutoValidateAntiforgeryToken
especificados a um nível superior (globalmente ou num controlador).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Atualizar os tokens após a autenticação
Os tokens devem ser atualizados depois de o utilizador ser autenticado, redirecionando-o para uma vista ou página Razor Páginas.
JavaScript, AJAX e SPAs
Em aplicativos tradicionais baseados em HTML, os tokens antifalsificação são passados para o servidor usando campos de formulário ocultos. Em aplicativos e SPAs modernos baseados em JavaScript, 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 os cookies forem usados para armazenar tokens de autenticação e autenticar solicitações de API no servidor, o CSRF é um problema 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 antifalsificação no cliente e enviar o token como um cabeçalho de solicitação é uma abordagem recomendada.
Blazor
Para obter mais informações, consulte ASP.NET Core Blazor authentication and authorization.
Javascript
Usando JavaScript com visualizações, o token pode ser criado usando um serviço de dentro da visualização. Injete o serviço de IAntiforgery na visualização e ligue para 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>
}
O exemplo anterior usa JavaScript para ler o valor de campo oculto para o cabeçalho AJAX POST.
Esta abordagem elimina a necessidade de lidar diretamente com a configuração de cookies do servidor ou lê-los a partir do cliente. No entanto, quando não for possível injetar o serviço IAntiforgery, use JavaScript para acessar tokens em cookies:
- Tokens de acesso em uma solicitação adicional ao servidor, tipicamente
same-origin
. - Use o conteúdo do cookiepara criar um cabeçalho com o valor do token.
Supondo que o script envie o token em um cabeçalho de solicitação chamado X-XSRF-TOKEN
, configure o serviço antifalsificação para procurar o cabeçalho X-XSRF-TOKEN
:
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
O exemplo a seguir adiciona um ponto de extremidade protegido que grava o token de solicitação em um cookielegível por JavaScript:
app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
var tokens = forgeryService.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
new CookieOptions { HttpOnly = false });
return Results.Ok();
}).RequireAuthorization();
O exemplo a seguir usa JavaScript para fazer uma solicitação AJAX para obter o token e fazer outra solicitação com o cabeçalho apropriado:
var response = await fetch("/antiforgery/token", {
method: "GET",
headers: { "Authorization": authorizationToken }
});
if (response.ok) {
// https://developer.mozilla.org/docs/web/api/document/cookie
const xsrfToken = document.cookie
.split("; ")
.find(row => row.startsWith("XSRF-TOKEN="))
.split("=")[1];
response = await fetch("/JavaScript/FetchEndpoint", {
method: "POST",
headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
Observação
Quando o token antifalsificação é fornecido no cabeçalho da solicitação e na carga útil do formulário, somente o token no cabeçalho é validado.
Antifalsificação com APIs mínimas
Chame AddAntiforgery e UseAntiforgery(IApplicationBuilder) para registar os serviços de antifalsificação na DI. Os tokens antifalsificação são usados para mitigar ataques de falsificação de solicitação entre sites.
var builder = WebApplication.CreateBuilder();
builder.Services.AddAntiforgery();
var app = builder.Build();
app.UseAntiforgery();
app.MapGet("/", () => "Hello World!");
app.Run();
O middleware de antifalsificação de software:
- Não curto-circuita na execução do rest do pipeline de requisição.
- Defina o IAntiforgeryValidationFeature no HttpContext.Features da solicitação atual.
O token antifalsificação só é validado se:
- O endpoint contém metadados implementando IAntiforgeryMetadata nos quais
RequiresValidation=true
. - O método HTTP associado ao ponto de extremidade é um método HTTP relevante . Os métodos relevantes são todos os métodos HTTP exceto TRACE, OPTIONS, HEAD e GET.
- A solicitação está associada a um ponto de extremidade válido.
Nota: Quando ativado manualmente, o middleware antifalsificação deve ser executado após o middleware de autenticação e autorização para impedir a leitura de dados de formulário quando o usuário não é autenticado.
Por padrão, APIs mínimas que aceitam dados de formulário exigem validação de token antifalsificação.
Considere o seguinte método GenerateForm
:
public static string GenerateForm(string action,
AntiforgeryTokenSet token, bool UseToken=true)
{
string tokenInput = "";
if (UseToken)
{
tokenInput = $@"<input name=""{token.FormFieldName}""
type=""hidden"" value=""{token.RequestToken}"" />";
}
return $@"
<html><body>
<form action=""{action}"" method=""POST"" enctype=""multipart/form-data"">
{tokenInput}
<input type=""text"" name=""name"" />
<input type=""date"" name=""dueDate"" />
<input type=""checkbox"" name=""isCompleted"" />
<input type=""submit"" />
</form>
</body></html>
";
}
O código anterior tem três argumentos, a ação, o token antifalsificação e um bool
indicando se o token deve ser usado.
Considere o seguinte exemplo:
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder();
builder.Services.AddAntiforgery();
var app = builder.Build();
app.UseAntiforgery();
// Pass token
app.MapGet("/", (HttpContext context, IAntiforgery antiforgery) =>
{
var token = antiforgery.GetAndStoreTokens(context);
return Results.Content(MyHtml.GenerateForm("/todo", token), "text/html");
});
// Don't pass a token, fails
app.MapGet("/SkipToken", (HttpContext context, IAntiforgery antiforgery) =>
{
var token = antiforgery.GetAndStoreTokens(context);
return Results.Content(MyHtml.GenerateForm("/todo",token, false ), "text/html");
});
// Post to /todo2. DisableAntiforgery on that endpoint so no token needed.
app.MapGet("/DisableAntiforgery", (HttpContext context, IAntiforgery antiforgery) =>
{
var token = antiforgery.GetAndStoreTokens(context);
return Results.Content(MyHtml.GenerateForm("/todo2", token, false), "text/html");
});
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));
app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
.DisableAntiforgery();
app.Run();
class Todo
{
public required string Name { get; set; }
public bool IsCompleted { get; set; }
public DateTime DueDate { get; set; }
}
public static class MyHtml
{
public static string GenerateForm(string action,
AntiforgeryTokenSet token, bool UseToken=true)
{
string tokenInput = "";
if (UseToken)
{
tokenInput = $@"<input name=""{token.FormFieldName}""
type=""hidden"" value=""{token.RequestToken}"" />";
}
return $@"
<html><body>
<form action=""{action}"" method=""POST"" enctype=""multipart/form-data"">
{tokenInput}
<input type=""text"" name=""name"" />
<input type=""date"" name=""dueDate"" />
<input type=""checkbox"" name=""isCompleted"" />
<input type=""submit"" />
</form>
</body></html>
";
}
}
No código anterior, posta para:
-
/todo
exige um token antifalsificação válido. -
/todo2
não exige um token antifalsificação válido porqueDisableAntiforgery
é chamado.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));
app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
.DisableAntiforgery();
Um POST para:
-
/todo
do formulário gerado pelo ponto de extremidade/
é bem-sucedido porque o token antifalsificação é válido. -
/todo
do formulário gerado pelo/SkipToken
falha porque o antifalsificação não está incluído. -
/todo2
do formulário gerado pelo ponto de extremidade/DisableAntiforgery
tem sucesso porque a proteção contra falsificação não é necessária.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));
app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
.DisableAntiforgery();
Quando um formulário é enviado sem um token antifalsificação válido:
- No ambiente de desenvolvimento, uma exceção é lançada.
- No ambiente de produção, uma mensagem é registrada.
Cookies de autenticação e antifalsificação do Windows
Ao usar a Autenticação do Windows, os pontos de extremidade da aplicação devem ser protegidos contra ataques CSRF da mesma maneira que são protegidos os cookies. O navegador envia implicitamente o contexto de autenticação para o servidor e os endpoints precisam ser protegidos contra ataques CSRF.
Estender a antifalsificação
O tipo IAntiforgeryAdditionalDataProvider permite que os desenvolvedores estendam o comportamento do sistema anti-CSRF ao incluir dados adicionais em cada token. O método GetAdditionalData é chamado cada vez que um token de campo é gerado, e o valor de retorno é incorporado 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á incorporado nos tokens gerados, portanto, não há necessidade de incluir essas informações. Se um token incluir dados suplementares, mas nenhum IAntiForgeryAdditionalDataProvider
estiver configurado, os dados suplementares 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 pelo qual 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 a cada solicitação para um site. Essa forma de exploração também é conhecida como ataque de um só clique ou captura de sessão , porque o ataque tira proveito da sessão previamente autenticada do utilizador.
Um exemplo de um ataque CSRF:
Um utilizador entra no
www.good-banking-site.example.com
usando a autenticação de formulários. O servidor autentica o usuário e emite uma resposta que inclui uma autenticação cookie. O site é vulnerável a ataques porque confia em qualquer solicitação recebida com uma autenticação válida cookie.O utilizador visita um site malicioso,
www.bad-crook-site.example.com
.O site mal-intencionado,
www.bad-crook-site.example.com
, contém um formulário HTML semelhante ao exemplo a seguir:<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 o
action
do formulário envia para o site vulnerável, não para o site mal-intencionado. Esta é a parte "cross-site" da CSRF.O usuário seleciona o botão enviar. O navegador faz a solicitação e inclui automaticamente a autenticação cookie do domínio solicitado,
www.good-banking-site.example.com
.A solicitação é executada no servidor
www.good-banking-site.example.com
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 de 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, caso no qual uma etiqueta de imagem pode ser usada para executar a ação. Esta forma de ataque é comum em sites de fóruns que permitem imagens, mas bloqueiam JavaScript. Os aplicativos que mudam de estado em solicitações GET, onde variáveis ou recursos são alterados, são vulneráveis a ataques mal-intencionados. As solicitações GET que mudam de estado são inseguras. Uma prática recomendada é nunca alterar o estado em uma solicitação GET.
Os ataques CSRF são possíveis contra aplicativos da Web que usam cookies para autenticação porque:
- Os navegadores armazenam cookies emitidos por um aplicativo da Web.
- Os cookies armazenados incluem cookies de sessão para utilizadores 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 de cookies. Por exemplo, as autenticações Basic e Digest também são vulneráveis. Depois que um usuário entra com autenticação Básica ou Digest, o navegador envia automaticamente as credenciais até que a sessão termine.
Neste contexto, sessão refere-se à sessão do lado do cliente durante a qual o usuário é autenticado. Não está relacionado com sessões do lado do servidor ou ASP.NET Core Session Middleware.
Os usuários podem se proteger contra vulnerabilidades CSRF tomando precauções:
- Saia dos aplicativos Web quando terminar de usá-los.
- Limpe os cookies do navegador periodicamente.
No entanto, as vulnerabilidades CSRF são fundamentalmente um problema com o aplicativo Web, não com o usuário final.
Fundamentos de autenticação
A autenticação baseada em Cookieé uma forma popular de autenticação. Os sistemas de autenticação baseados em tokens estão crescendo em popularidade, especialmente para aplicativos de página única (SPAs).
Autenticação baseada em Cookie
Quando um usuário se autentica usando seu nome de usuário e senha, ele recebe 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 feita pelo cliente. A geração e validação desse cookie é realizada pelo Cookie Authentication Middleware. O middleware serializa uma entidade de usuário em um cookiecriptografado. Em solicitações subsequentes, o middleware valida o cookie, recria o principal e atribui o principal à propriedade HttpContext.User.
Autenticação baseada em tokens
Quando um usuário é autenticado, ele recebe um token (não um token antifalsificação). O token contém informações do utilizador na forma de declarações ou um token de referência que direciona a aplicação para o estado do utilizador que é mantido na aplicação. 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 de portador. Esta abordagem torna a aplicação sem estado. Em cada solicitação subsequente, o token é passado na solicitação de validação do lado do servidor. Este token não é criptografado; é codificado. No servidor, o token é decodificado para acessar suas informações. Para enviar o token em solicitações subsequentes, armazene-o no armazenamento local do navegador. Colocar um token no armazenamento local do navegador e recuperá-lo e usá-lo como um token de portador fornece proteção contra ataques CSRF. No entanto, se o aplicativo estiver vulnerável à injeção de script via XSS ou um arquivo javascript externo comprometido, um ciberinvasor pode recuperar qualquer valor do armazenamento local e enviá-lo para si mesmo. ASP.NET Core codifica todas as saídas do lado do servidor de variáveis por padrão, reduzindo o risco de XSS. Se sobrescrever este comportamento usando Html.Raw ou código personalizado com entrada não confiável, pode aumentar o risco de XSS.
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 num cookie. Para obter mais informações, consulte o problema do GitHub, no qual o exemplo de código SPA acrescenta dois cookies.
Vários aplicativos hospedados em um domínio
Os ambientes de hospedagem compartilhada são vulneráveis a sequestro de sessão, CSRF de login e outros ataques.
Embora example1.contoso.net
e example2.contoso.net
sejam hosts diferentes, há uma relação de confiança implícita entre hosts sob o domínio *.contoso.net
. Essa relação de confiança implícita permite que hosts potencialmente não confiáveis afetem os cookies uns dos outros (as políticas de mesma origem que regem as solicitações AJAX não se aplicam necessariamente aos cookies HTTP).
Os ataques que exploram cookies confiáveis entre aplicativos hospedados no mesmo domínio podem ser evitados não compartilhando domínios. Quando cada aplicativo é hospedado em seu próprio domínio, não há nenhuma relação de confiança implícita cookie para explorar.
Antifalsificação no ASP.NET Core
Advertência
ASP.NET Core implementa antifalsificação usando ASP.NET Core Data Protection. A pilha de proteção de dados deve ser configurada para funcionar em um grupo de servidores. Para obter mais informações, consulte Configurando a proteção de dados.
O middleware de antifalsificação é adicionado ao contentor de injeção de dependência do
O FormTagHelper injeta tokens antifalsificação em elementos de formulário HTML. A marcação a seguir em um arquivo Razor gera automaticamente tokens antifalsificação:
<form method="post">
<!-- ... -->
</form>
Da mesma forma, IHtmlHelper.BeginForm gera tokens antifalsificação por padrão se o método do formulário não for GET.
A geração automática de tokens antifalsificação para elementos de formulário HTML acontece quando a tag <form>
contém o atributo method="post"
e uma das seguintes opções é verdadeira:
- O atributo action está vazio (
action=""
). - O atributo action não é fornecido (
<form method="post">
).
A geração automática de tokens antifalsificação para elementos de formulário HTML pode ser desativada:
Desative explicitamente os tokens antifalsificação com o atributo
asp-antiforgery
:<form method="post" asp-antiforgery="false"> <!-- ... --> </form>
O elemento de formulário é excluído dos Auxiliares de Etiqueta ao usar o símbolo de exclusão de Auxiliar de Etiqueta !:
<!form method="post"> <!-- ... --> </!form>
Remova o
FormTagHelper
da visualização. OFormTagHelper
pode ser removido de um modo de exibição adicionando a seguinte diretiva ao modo de exibição Razor:@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Observação
Razor Páginas são automaticamente protegidas 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 Synchronizer Token Pattern (STP). O STP é usado quando o usuário solicita uma página com dados de formulário:
- O servidor envia um token associado ao identity do usuário atual para o cliente.
- O cliente envia de volta o token para o servidor para verificação.
- Se o servidor receber um token que não corresponde ao identitydo usuário autenticado, a solicitação será rejeitada.
O token é único 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ção de: página 1 > página 2 > página 3). Todos os formulários nos modelos ASP.NET Core MVC e Razor Pages geram tokens antifalsificação. O seguinte par de exemplos de exibição gera tokens antifalsificação:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Adicione explicitamente um token antifalsificação a um elemento <form>
sem usar Tag Helpers com o HTML helper @Html.AntiForgeryToken
:
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
Em cada um dos casos anteriores, o ASP.NET Core adiciona um campo de formulário oculto semelhante ao exemplo a seguir:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core inclui três filtros para trabalhar com tokens antifalsificação:
Antifalsificação com AddControllers
Chamar AddControllersnão habilita tokens antifalsificação. A função AddControllersWithViews deve ser chamada para ter suporte de token antifalsificação integrado.
Várias abas do navegador e o esquema de token do sincronizador
Com o Synchronizer Token Pattern, apenas a página carregada mais recentemente contém um token antifalsificação válido. O uso de várias guias pode ser problemático. Por exemplo, se um usuário abrir várias guias:
- Apenas o separador carregado mais recentemente contém um token antifalsificação válido.
- Solicitações originadas em 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 proteção contra falsificação com AntiforgeryOptions
Personalize 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 de antifalsificação de Cookie
usando as propriedades da classe CookieBuilder, conforme mostrado na tabela a seguir.
Opção | Descrição |
---|---|
Cookie | Determina as configurações usadas para criar os cookies antifalsificação. |
FormFieldName | O nome do campo de formulário oculto usado pelo sistema antifalsificação para renderizar tokens antifalsificação em visualizações. |
HeaderName | O nome do cabeçalho usado pelo sistema antifalsificação. Se null , o sistema considera apenas os dados do formulário. |
SuppressXFrameOptionsHeader | Especifica se a geração do cabeçalho X-Frame-Options deve ser suprimida. Por padrão, o cabeçalho é gerado com um valor de "SAMEORIGIN". O padrão é false . |
Para obter mais informações, consulte CookieAuthenticationOptions.
Gere tokens antifalsificação com IAntiforgery
IAntiforgery fornece a API para configurar recursos antifalsificação.
IAntiforgery
pode ser solicitado em Program.cs
usando WebApplication.Services. O exemplo a seguir utiliza o middleware da página home da aplicação para gerar um token antifraude 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 chamado XSRF-TOKEN
. O cliente pode ler essa cookie e fornecer seu valor como um cabeçalho anexado às solicitações AJAX. Por exemplo, o Angular inclui proteção XSRF integrada , que por padrão lê um cookie chamado XSRF-TOKEN
.
Exigir validação antifalsificação
O filtro de ação ValidateAntiForgeryToken pode ser aplicado a uma ação específica, a um controlador ou globalmente. As solicitações feitas para ações que têm esse filtro aplicado são bloqueadas, a menos que a solicitação inclua um token antifalsificação válido:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
O atributo ValidateAntiForgeryToken
requer um token para solicitações para os métodos de ação que ele marca, incluindo solicitações HTTP GET. Se o atributo ValidateAntiForgeryToken
for aplicado nos controladores do aplicativo, ele poderá ser substituído pelo atributo IgnoreAntiforgeryToken
.
Valide automaticamente tokens antifalsificação apenas para métodos HTTP inseguros
Em vez de aplicar amplamente o atributo ValidateAntiForgeryToken
e, em seguida, substituí-los por atributos IgnoreAntiforgeryToken
, pode ser usado o atributo AutoValidateAntiforgeryToken. Esse atributo funciona de forma idêntica ao atributo ValidateAntiForgeryToken
, exceto que ele não requer tokens para solicitações feitas usando os seguintes métodos HTTP:
- OBTER
- CABEÇA
- OPÇÕES
- RASTREIO
Recomendamos o uso de AutoValidateAntiforgeryToken
de forma ampla para cenários que não sejam de API. Esse atributo garante que as ações POST sejam protegidas por padrão. A alternativa é ignorar os tokens de proteção contra falsificação por padrão, a não ser que se aplique ValidateAntiForgeryToken
a métodos 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 antifalsificação.
As APIs não têm um mecanismo automático para enviar a parte nãocookie 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 antifalsificação globais ou do controlador
O filtro IgnoreAntiforgeryToken é utilizado para eliminar a necessidade de um token de antifalsificação numa ação (ou controlador) específica. Quando aplicado, este filtro substitui os filtros ValidateAntiForgeryToken
e AutoValidateAntiforgeryToken
especificados a um nível superior (globalmente ou num controlador).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Atualizar tokens após a autenticação
Os tokens devem ser atualizados após o utilizador ser autenticado, sendo redirecionado para uma visualização ou uma página da Razor Pages.
JavaScript, AJAX e SPAs
Em aplicativos tradicionais baseados em HTML, os tokens antifalsificação são passados para o servidor usando campos de formulário ocultos. Em aplicativos e SPAs modernos baseados em JavaScript, 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 os cookies forem usados para armazenar tokens de autenticação e autenticar solicitações de API no servidor, o CSRF é um problema 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 antifalsificação no cliente e enviar o token como um cabeçalho de solicitação é uma abordagem recomendada.
Javascript
Usando JavaScript com visualizações, o token pode ser criado usando um serviço de dentro da visualização. Injete o serviço de IAntiforgery na visualização e ligue para 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>
}
O exemplo anterior usa JavaScript para ler o valor de campo oculto para o cabeçalho AJAX POST.
Esta abordagem elimina a necessidade de lidar diretamente com a configuração de cookies do servidor ou lê-los a partir do cliente. No entanto, quando não for possível injetar o serviço IAntiforgery, use JavaScript para acessar tokens em cookies:
- Tokens de acesso em uma solicitação adicional ao servidor, normalmente
same-origin
. - Use o conteúdo do cookiepara criar um cabeçalho com o valor do token.
Supondo que o script envie o token em um cabeçalho de solicitação chamado X-XSRF-TOKEN
, configure o serviço antifalsificação para procurar o cabeçalho X-XSRF-TOKEN
:
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
O exemplo a seguir adiciona um ponto de extremidade protegido que grava o token de solicitação em um cookielegível por JavaScript:
app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
var tokens = forgeryService.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
new CookieOptions { HttpOnly = false });
return Results.Ok();
}).RequireAuthorization();
O exemplo a seguir usa JavaScript para fazer uma solicitação AJAX para obter o token e fazer outra solicitação com o cabeçalho apropriado:
var response = await fetch("/antiforgery/token", {
method: "GET",
headers: { "Authorization": authorizationToken }
});
if (response.ok) {
// https://developer.mozilla.org/docs/web/api/document/cookie
const xsrfToken = document.cookie
.split("; ")
.find(row => row.startsWith("XSRF-TOKEN="))
.split("=")[1];
response = await fetch("/JavaScript/FetchEndpoint", {
method: "POST",
headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
Observação
Quando o token antifalsificação é fornecido no cabeçalho da solicitação e na carga útil do formulário, somente o token no cabeçalho é validado.
Antifalsificação com APIs mínimas
Minimal APIs
não suportam o uso dos filtros incluídos (ValidateAntiForgeryToken
, AutoValidateAntiforgeryToken
, IgnoreAntiforgeryToken
), no entanto, IAntiforgery fornece as APIs necessárias para validar uma solicitação.
O exemplo a seguir cria um filtro que valida o token antifalsificação:
internal static class AntiForgeryExtensions
{
public static TBuilder ValidateAntiforgery<TBuilder>(this TBuilder builder) where TBuilder : IEndpointConventionBuilder
{
return builder.AddEndpointFilter(routeHandlerFilter: async (context, next) =>
{
try
{
var antiForgeryService = context.HttpContext.RequestServices.GetRequiredService<IAntiforgery>();
await antiForgeryService.ValidateRequestAsync(context.HttpContext);
}
catch (AntiforgeryValidationException)
{
return Results.BadRequest("Antiforgery token validation failed.");
}
return await next(context);
});
}
}
O filtro pode então ser aplicado a um ponto de extremidade:
app.MapPost("api/upload", (IFormFile name) => Results.Accepted())
.RequireAuthorization()
.ValidateAntiforgery();
Cookies de autenticação e antifalsificação do Windows
Ao usar a Autenticação do Windows, os pontos de extremidade do aplicativo devem ser protegidos contra ataques CSRF tal como se faz para cookies. O navegador envia implicitamente o contexto de autenticação para o servidor e os endpoints precisam ser protegidos contra ataques de CSRF.
Estender o mecanismo antifalsificação
O tipo IAntiforgeryAdditionalDataProvider permite que os desenvolvedores estendam o comportamento do sistema anti-CSRF por ida e volta de dados adicionais em cada token. O método GetAdditionalData é chamado cada vez que um token de campo é gerado, e o valor de retorno é incorporado no token gerado. Um implementador pode retornar uma data/hora, um nonce ou qualquer outro valor e depois chamar ValidateAdditionalData para validar esses dados quando o token for validado. O nome de usuário do cliente já está incorporado nos tokens gerados, portanto, não há necessidade de incluir essas informações. Se um token incluir dados suplementares, mas nenhum IAntiForgeryAdditionalDataProvider
estiver configurado, os dados suplementares não serão validados.
Recursos adicionais
- Host ASP.NET Core em uma de web farm
A falsificação de solicitação entre sites (também conhecida como XSRF ou CSRF) é um ataque contra aplicativos hospedados na Web pelo qual 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 a cada solicitação para um site. Essa forma de exploração também é conhecida como de ataque com um clique ou sessão de porque o ataque aproveita a sessão previamente autenticada do usuário.
Um exemplo de um ataque CSRF:
Um utilizador inicia sessão no
www.good-banking-site.example.com
usando a autenticação de formulários. O servidor autentica o usuário e emite uma resposta que inclui uma autenticação cookie. O site é vulnerável a ataques porque confia em qualquer solicitação recebida com uma autenticação válida cookie.O utilizador visita um site malicioso,
www.bad-crook-site.example.com
.O site mal-intencionado,
www.bad-crook-site.example.com
, contém um formulário HTML semelhante ao exemplo a seguir:<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 o
action
do formulário envia para o site vulnerável, não para o site mal-intencionado. Esta é a parte "cross-site" da CSRF.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.example.com
.A solicitação é executada no servidor
www.good-banking-site.example.com
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 de https://www.good-banking-site.com/
tão facilmente quanto pode enviar uma solicitação insegura.
Alguns ataques têm como alvo endereços finais que respondem a solicitações GET, caso em que é possível usar uma tag de imagem para executar a ação. Esta forma de ataque é comum em sites de fóruns que permitem imagens, mas bloqueiam JavaScript. Os aplicativos que mudam de estado em solicitações GET, onde variáveis ou recursos são alterados, são vulneráveis a ataques mal-intencionados. As solicitações GET que mudam de estado são inseguras. Uma prática recomendada é nunca alterar o estado em uma solicitação GET.
Os ataques CSRF são possíveis contra aplicativos da Web que usam cookies para autenticação porque:
- Os navegadores armazenam cookies emitidos por um aplicativo da Web.
- Os cookies armazenados incluem cookies de sessão para utilizadores 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 de cookies. Por exemplo, as autenticações Basic e Digest também são vulneráveis. Depois que um usuário entra com autenticação Básica ou Digest, o navegador envia automaticamente as credenciais até que a sessão termine.
Neste contexto, a sessão refere-se à sessão do lado do cliente durante a qual o utilizador é autenticado. Não está relacionado com sessões do lado do servidor ou ASP.NET Core Session Middleware.
Os usuários podem se proteger contra vulnerabilidades CSRF tomando precauções:
- Saia dos aplicativos Web quando terminar de usá-los.
- Limpe os cookies do navegador periodicamente.
No entanto, as vulnerabilidades CSRF são fundamentalmente um problema com o aplicativo Web, não com o usuário final.
Fundamentos de autenticação
A autenticação baseada em Cookieé uma forma popular de autenticação. Os sistemas de autenticação baseados em tokens estão crescendo em popularidade, especialmente para aplicativos de página única (SPAs).
Autenticação baseada em Cookie
Quando um usuário se autentica usando seu nome de usuário e senha, ele recebe 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 feita pelo cliente. A geração e validação desse cookie é realizada pelo Cookie Authentication Middleware. O middleware serializa uma entidade de usuário em um cookiecriptografado. Em solicitações subsequentes, o middleware valida o cookie, recria o principal e atribui o principal à propriedade HttpContext.User.
Autenticação baseada em tokens
Quando um usuário é autenticado, ele recebe um token (não um token antifalsificação). O token contém informações do utilizador na forma de declarações ou um token de referência que direciona a aplicação para o estado do utilizador mantido na aplicação. 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 de portador. Essa abordagem torna a aplicação sem estado. Em cada solicitação subsequente, o token é passado na solicitação de validação do lado do servidor. Este token não é criptografado; é codificado. No servidor, o token é decodificado para acessar suas informações. Para enviar o token em solicitações subsequentes, armazene-o 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 mais informações, consulte o problema do GitHub . O exemplo de código SPA adiciona dois cookies.
Vários aplicativos hospedados em um domínio
Os ambientes de hospedagem compartilhada são vulneráveis a sequestro de sessão, CSRF de login e outros ataques.
Embora example1.contoso.net
e example2.contoso.net
sejam hosts diferentes, há uma relação de confiança implícita entre hosts sob o domínio *.contoso.net
. Essa relação de confiança implícita permite que hosts potencialmente não confiáveis afetem os cookies uns dos outros (as políticas de mesma origem que regem as solicitações AJAX não se aplicam necessariamente aos cookies HTTP).
Os ataques que exploram cookies confiáveis entre aplicativos hospedados no mesmo domínio podem ser evitados não compartilhando domínios. Quando cada aplicativo é hospedado em seu próprio domínio, não há nenhuma relação de confiança implícita cookie para explorar.
Antifalsificação no ASP.NET Core
Advertência
ASP.NET Core implementa antifalsificação usando ASP.NET Core Data Protection. A pilha de proteção de dados deve ser configurada para funcionar numa fazenda de servidores. Para obter mais informações, consulte Configurando a proteção de dados.
O middleware antifalsificação é adicionado ao contentor de injeção de dependência do
O FormTagHelper injeta tokens antifalsificação em elementos de formulário HTML. A marcação a seguir em um arquivo Razor gera automaticamente tokens antifalsificação:
<form method="post">
<!-- ... -->
</form>
Da mesma forma, IHtmlHelper.BeginForm gera tokens antifalsificação por padrão se o método do formulário não for GET.
A geração automática de tokens antifalsificação para elementos de formulário HTML acontece quando a tag <form>
contém o atributo method="post"
e uma das seguintes opções é verdadeira:
- O atributo action está vazio (
action=""
). - O atributo action não é fornecido (
<form method="post">
).
A geração automática de tokens antifalsificação para elementos de formulário HTML pode ser desativada:
Desative explicitamente os tokens antifalsificação com o atributo
asp-antiforgery
:<form method="post" asp-antiforgery="false"> <!-- ... --> </form>
O elemento de formulário é desativado dos Auxiliares de Tag usando o Auxiliar de Tag ! símbolo de exclusão:
<!form method="post"> <!-- ... --> </!form>
Remova o
FormTagHelper
da vista. OFormTagHelper
pode ser removido de um modo de exibição adicionando a seguinte diretiva ao modo de exibição Razor:@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Observação
Razor Páginas são automaticamente protegidas 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 Synchronizer Token Pattern (STP). O STP é usado quando o usuário solicita uma página com dados de formulário:
- O servidor envia um token associado ao identity do usuário atual para o cliente.
- O cliente envia de volta o token para o servidor para verificação.
- Se o servidor receber um token que não corresponde ao identitydo usuário autenticado, a solicitação será rejeitada.
O token é único 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ção de: página 1 > página 2 > página 3). Todos os formulários nos modelos ASP.NET Core MVC e Razor Pages geram tokens antifalsificação. O seguinte par de exemplos de exibição gera tokens antifalsificação:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Adicione explicitamente um token antifalsificação a um elemento <form>
sem usar Tag Helpers com o HTML helper @Html.AntiForgeryToken
:
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
Em cada um dos casos anteriores, o ASP.NET Core adiciona um campo de formulário oculto semelhante ao exemplo a seguir:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core inclui três filtros para trabalhar com tokens antifalsificação:
Antifalsificação com AddControllers
Chamar AddControllersnão ativa tokens antifalsificação. AddControllersWithViews precisa ser chamado para ter suporte de token de antifalsificação integrado.
Várias abas do navegador e o padrão de token de sincronização
Com o Synchronizer Token Pattern, apenas a página carregada mais recentemente contém um token antifalsificação válido. O uso de várias guias pode ser problemático. Por exemplo, se um usuário abrir várias guias:
- Apenas o separador carregado mais recentemente contém um token antifalsificação válido.
- Solicitações feitas de guias carregadas anteriormente resultam num 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 o antifalsificação com o AntiforgeryOptions
Personalize 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 antifalsificação de Cookie
usando as propriedades da classe CookieBuilder, conforme mostrado na tabela a seguir.
Opção | Descrição |
---|---|
Cookie | Determina as configurações usadas para criar os cookies antifalsificação. |
FormFieldName | O nome do campo de formulário oculto usado pelo sistema antifalsificação para renderizar tokens antifalsificação em visualizações. |
HeaderName | O nome do cabeçalho usado pelo sistema antifalsificação. Se null , o sistema considera apenas os dados do formulário. |
SuppressXFrameOptionsHeader | Especifica se a geração do cabeçalho X-Frame-Options deve ser suprimida. Por padrão, o cabeçalho é gerado com um valor de "SAMEORIGIN". O padrão é false . |
Para obter mais informações, consulte CookieAuthenticationOptions.
Gere tokens antifalsificação com IAntiforgery
IAntiforgery fornece a API para configurar recursos antifalsificação.
IAntiforgery
pode ser solicitado em Program.cs
usando WebApplication.Services. O exemplo a seguir usa middleware da página de home do aplicativo para gerar um token antifalsificação 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 chamado XSRF-TOKEN
. O cliente pode ler essa cookie e fornecer seu valor como um cabeçalho anexado às solicitações AJAX. Por exemplo, o Angular inclui de proteção XSRF integrada que lê um cookie chamado XSRF-TOKEN
por padrão.
Exigir validação antifalsificação
O filtro de ação ValidateAntiForgeryToken pode ser aplicado a uma ação individual, a um controlador ou de forma global. As solicitações feitas para ações que têm esse filtro aplicado são bloqueadas, a menos que a solicitação inclua um token antifalsificação válido:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
O atributo ValidateAntiForgeryToken
requer um token para solicitações para os métodos de ação que ele marca, incluindo solicitações HTTP GET. Se o atributo ValidateAntiForgeryToken
for aplicado nos controladores do aplicativo, ele poderá ser substituído pelo atributo IgnoreAntiforgeryToken
.
Valide automaticamente tokens antifalsificação apenas para métodos HTTP inseguros
Em vez de aplicar amplamente o atributo ValidateAntiForgeryToken
e, em seguida, substituí-los por atributos IgnoreAntiforgeryToken
, o atributo AutoValidateAntiforgeryToken pode ser usado. Esse atributo funciona de forma idêntica ao atributo ValidateAntiForgeryToken
, exceto que ele não requer tokens para solicitações feitas usando os seguintes métodos HTTP:
- OBTER
- CABEÇA
- OPÇÕES
- RASTREIO
Recomendamos o uso de AutoValidateAntiforgeryToken
de forma ampla para cenários que não sejam de API. Esse atributo garante que as ações POST sejam protegidas por padrão. A alternativa é ignorar por padrão os tokens antifalsificação, salvo se ValidateAntiForgeryToken
for aplicado a métodos 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 antifalsificação.
As APIs não têm um mecanismo automático para enviar a parte nãocookie 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());
});
Sobrepor atributos antifalsificação globais ou do controlador
O filtro IgnoreAntiforgeryToken é usado para eliminar a necessidade de um token antifalsificação para uma determinada ação (ou controlador). Quando aplicado, este filtro substitui os filtros ValidateAntiForgeryToken
e AutoValidateAntiforgeryToken
especificados a um nível superior (globalmente ou a um controlador).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Atualizar tokens após a autenticação
Os tokens devem ser atualizados depois que o utilizador é autenticado, redirecionando-o para uma vista ou página Razor.
JavaScript, AJAX e SPAs
Em aplicativos tradicionais baseados em HTML, os tokens antifalsificação são passados para o servidor usando campos de formulário ocultos. Em aplicativos e SPAs modernos baseados em JavaScript, 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 os cookies forem usados para armazenar tokens de autenticação e autenticar solicitações de API no servidor, o CSRF é um problema 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 antifalsificação no cliente e enviar o token como um cabeçalho de solicitação é uma abordagem recomendada.
Javascript
Usando JavaScript com visualizações, o token pode ser criado usando um serviço de dentro da visualização. Injete o serviço de IAntiforgery na visualização e ligue para 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>
}
O exemplo anterior usa JavaScript para ler o valor de campo oculto para o cabeçalho AJAX POST.
Esta abordagem elimina a necessidade de lidar diretamente com a configuração de cookies do servidor ou lê-los a partir do cliente. No entanto, quando não é possível injetar o serviço IAntiforgery, o JavaScript também pode acessar o token em cookies, obtido a partir de uma solicitação adicional ao servidor (geralmente same-origin
), e usar o conteúdo do cookiepara criar um cabeçalho com o valor do token.
Supondo que o script envie o token em um cabeçalho de solicitação chamado X-XSRF-TOKEN
, configure o serviço antifalsificação para procurar o cabeçalho X-XSRF-TOKEN
:
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
O exemplo a seguir adiciona um ponto de extremidade protegido que gravará o token de solicitação em um cookielegível por JavaScript:
app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
var tokens = forgeryService.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
new CookieOptions { HttpOnly = false });
return Results.Ok();
}).RequireAuthorization();
O exemplo a seguir usa JavaScript para fazer uma solicitação AJAX para obter o token e fazer outra solicitação com o cabeçalho apropriado:
var response = await fetch("/antiforgery/token", {
method: "GET",
headers: { "Authorization": authorizationToken }
});
if (response.ok) {
// https://developer.mozilla.org/docs/web/api/document/cookie
const xsrfToken = document.cookie
.split("; ")
.find(row => row.startsWith("XSRF-TOKEN="))
.split("=")[1];
response = await fetch("/JavaScript/FetchEndpoint", {
method: "POST",
headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
Cookies de autenticação e antifalsificação do Windows
Ao usar a Autenticação do Windows, os pontos de extremidade do aplicativo devem ser protegidos contra ataques CSRF da mesma forma que para cookies. O navegador envia implicitamente o contexto de autenticação para o servidor, assim, os pontos de extremidade precisam ser protegidos contra ataques CSRF.
Estender o mecanismo antifalsificação
O tipo IAntiforgeryAdditionalDataProvider permite que os desenvolvedores expandam o comportamento do sistema anti-CSRF ao incluir dados adicionais em cada token. O método GetAdditionalData é chamado cada vez que um token de campo é gerado, e o valor de retorno é incorporado 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á incorporado nos tokens gerados, portanto, não há necessidade de incluir essas informações. Se um token incluir dados suplementares, mas nenhum IAntiForgeryAdditionalDataProvider
estiver configurado, os dados suplementares 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 pelo qual 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 a cada solicitação para um site. Essa forma de exploração também é conhecida como de ataque com um clique ou sessão de porque o ataque aproveita a sessão previamente autenticada do usuário.
Um exemplo de ataque CSRF:
Um utilizador entra no
www.good-banking-site.example.com
usando a autenticação de formulários. O servidor autentica o usuário e emite uma resposta que inclui uma autenticação cookie. O site é vulnerável a ataques porque confia em qualquer solicitação recebida com uma autenticação válida cookie.O utilizador visita um site malicioso,
www.bad-crook-site.example.com
.O site mal-intencionado,
www.bad-crook-site.example.com
, contém um formulário HTML semelhante ao exemplo a seguir:<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 o
action
do formulário envia para o site vulnerável, não para o site mal-intencionado. Esta é a parte «inter-site» da CSRF.O usuário seleciona o botão enviar. O navegador faz o pedido e automaticamente inclui a autenticação cookie para o domínio solicitado,
www.good-banking-site.example.com
.A solicitação é executada no servidor
www.good-banking-site.example.com
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 de https://www.good-banking-site.com/
tão facilmente quanto pode enviar uma solicitação insegura.
Alguns ataques têm como alvo endpoints que respondem a solicitações GET, caso em que uma etiqueta de imagem pode ser usada para executar a ação. Esta forma de ataque é comum em sites de fóruns que permitem imagens, mas bloqueiam JavaScript. Os aplicativos que mudam de estado em solicitações GET, onde variáveis ou recursos são alterados, são vulneráveis a ataques mal-intencionados. As solicitações GET que mudam de estado são inseguras. Uma prática recomendada é nunca alterar o estado em uma solicitação GET.
Os ataques CSRF são possíveis contra aplicativos da Web que usam cookies para autenticação porque:
- Os navegadores armazenam cookies emitidos por um aplicativo da Web.
- Os cookies armazenados incluem cookies de sessão para utilizadores 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 de cookies. Por exemplo, as autenticações Basic e Digest também são vulneráveis. Depois que um usuário entra com autenticação Básica ou Digest, o navegador envia automaticamente as credenciais até que a sessão termine.
Neste contexto, a sessão refere-se à sessão do lado do cliente durante a qual o utilizador é autenticado. Não está relacionado com sessões do lado do servidor ou ASP.NET Core Session Middleware.
Os usuários podem se proteger contra vulnerabilidades CSRF tomando precauções:
- Saia dos aplicativos Web quando terminar de usá-los.
- Limpe os cookies do navegador periodicamente.
No entanto, as vulnerabilidades CSRF são fundamentalmente um problema com o aplicativo Web, não com o usuário final.
Fundamentos de autenticação
A autenticação baseada em Cookieé uma forma popular de autenticação. Os sistemas de autenticação baseados em tokens estão crescendo em popularidade, especialmente para aplicativos de página única (SPAs).
Autenticação baseada em Cookie
Quando um usuário se autentica usando seu nome de usuário e senha, ele recebe 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 feita pelo cliente. A geração e validação desse cookie é realizada pelo Cookie Authentication Middleware. O middleware serializa uma entidade de usuário em um cookiecriptografado. Em solicitações subsequentes, o middleware valida o cookie, recria o principal, e atribui o principal à propriedade HttpContext.User.
Autenticação baseada em tokens
Quando um usuário é autenticado, ele recebe um token (não um token antifalsificação). O token contém informações de utilizadores na forma de declarações ou um token de referência que orienta a aplicação para o estado do utilizador mantido na própria aplicação. 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 de 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. Este token não é criptografado; é codificado. No servidor, o token é decodificado para acessar suas informações. Para enviar o token em solicitações subsequentes, armazene-o 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 problema no GitHub, onde o exemplo de código SPA adiciona dois cookies.
Vários aplicativos hospedados em um domínio
Os ambientes de hospedagem compartilhada são vulneráveis a sequestro de sessão, CSRF de login e outros ataques.
Embora example1.contoso.net
e example2.contoso.net
sejam hosts diferentes, há uma relação de confiança implícita entre hosts sob o domínio *.contoso.net
. Essa relação de confiança implícita permite que hosts potencialmente não confiáveis afetem os cookies uns dos outros (as políticas de mesma origem que regem as solicitações AJAX não se aplicam necessariamente aos cookies HTTP).
Os ataques que exploram cookies confiáveis entre aplicativos hospedados no mesmo domínio podem ser evitados não compartilhando domínios. Quando cada aplicativo é hospedado em seu próprio domínio, não há nenhuma relação de confiança implícita cookie para explorar.
Configuração antifraude do ASP.NET Core
Advertência
ASP.NET Core implementa antifalsificação usando ASP.NET Core Data Protection. A pilha de proteção de dados deve ser configurada para funcionar numa fazenda de servidores. Para obter mais informações, consulte Configurando a proteção de dados.
O middleware antifalsificação é adicionado ao contêiner de de injeção de dependência do
No ASP.NET Core 2.0 ou posterior, o FormTagHelper injeta tokens antifalsificação em elementos de formulário HTML. A marcação a seguir em um arquivo Razor gera automaticamente tokens antifalsificação:
<form method="post">
...
</form>
Da mesma forma, IHtmlHelper.BeginForm gera tokens antifalsificação por padrão se o método do formulário não for GET.
A geração automática de tokens antifalsificação para elementos de formulário HTML acontece quando a tag <form>
contém o atributo method="post"
e uma das seguintes opções é verdadeira:
- O atributo action está vazio (
action=""
). - O atributo action não é fornecido (
<form method="post">
).
A geração automática de tokens antifalsificação para elementos de formulário HTML pode ser desativada:
Desative explicitamente os tokens antifalsificação com o atributo
asp-antiforgery
:<form method="post" asp-antiforgery="false"> ... </form>
O elemento de formulário é excluído dos Auxiliares de Tag através do símbolo de exclusãodo Auxiliar de Tag
. <!form method="post"> ... </!form>
Remova o
FormTagHelper
da vista. OFormTagHelper
pode ser removido de um modo de exibição adicionando a seguinte diretiva ao modo de exibição Razor:@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Observação
Razor Páginas são automaticamente protegidas 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 Synchronizer Token Pattern (STP). O STP é usado quando o usuário solicita uma página com dados de formulário:
- O servidor envia um token associado ao identity do usuário atual para o cliente.
- O cliente envia de volta o token para o servidor para verificação.
- Se o servidor receber um token que não corresponde ao identitydo usuário autenticado, a solicitação será rejeitada.
O token é único 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ção de: página 1 > página 2 > página 3). Todos os formulários nos modelos ASP.NET Core MVC e Razor Pages geram tokens antifalsificação. O seguinte par de exemplos de exibição gera tokens antifalsificação:
<form asp-controller="Todo" asp-action="Create" method="post">
...
</form>
@using (Html.BeginForm("Create", "Todo"))
{
...
}
Adicione explicitamente um token antifalsificação a um elemento <form>
sem usar Tag Helpers com o HTML helper @Html.AntiForgeryToken
:
<form action="/" method="post">
@Html.AntiForgeryToken()
</form>
Em cada um dos casos anteriores, o ASP.NET Core adiciona um campo de formulário oculto semelhante ao exemplo a seguir:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core inclui três filtros para trabalhar com tokens antifalsificação:
Opções antifalsificação
Personalize AntiforgeryOptions em Startup.ConfigureServices
:
services.AddAntiforgery(options =>
{
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Defina as propriedades antifalsificação Cookie
utilizando as propriedades da classe CookieBuilder, conforme mostrado na tabela a seguir.
Opção | Descrição |
---|---|
Cookie | Determina as configurações usadas para criar os cookies antifalsificação. |
FormFieldName | O nome do campo de formulário oculto usado pelo sistema antifalsificação para renderizar tokens antifalsificação em visualizações. |
HeaderName | O nome do cabeçalho usado pelo sistema antifalsificação. Se null , o sistema considera apenas os dados do formulário. |
SuppressXFrameOptionsHeader | Especifica se a geração do cabeçalho X-Frame-Options deve ser suprimida. Por padrão, o cabeçalho é gerado com um valor de "SAMEORIGIN". O padrão é false . |
Para obter mais informações, consulte CookieAuthenticationOptions.
Configurar recursos antifalsificação com IAntiforgery
IAntiforgery fornece a API para configurar recursos antifalsificação.
IAntiforgery
pode ser solicitado no método Configure
da classe Startup
.
No exemplo a seguir:
- O middleware da página de home da aplicação é usado para gerar um token antifalsificação e enviá-lo na resposta como um cookie.
- O token de solicitação é enviado como um cookie legível por JavaScript com a convenção de nomenclatura padrão do 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 antifalsificação
ValidateAntiForgeryToken é um filtro de ação que pode ser aplicado a uma ação individual, a um controlador ou globalmente. As solicitações feitas para ações que têm esse filtro aplicado são bloqueadas, a menos que a solicitação inclua um token antifalsificação 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 atributo ValidateAntiForgeryToken
requer um token para solicitações para os métodos de ação que ele marca, incluindo solicitações HTTP GET. Se o atributo ValidateAntiForgeryToken
for aplicado nos controladores do aplicativo, ele poderá ser substituído pelo atributo IgnoreAntiforgeryToken
.
Observação
ASP.NET Core não suporta a adição automática de tokens antifalsificação às solicitações GET.
Valide automaticamente tokens antifalsificação apenas para métodos HTTP inseguros
ASP.NET aplicativos principais não geram tokens antifalsificação para métodos HTTP seguros (GET, HEAD, OPTIONS e TRACE). Em vez de aplicar amplamente o atributo ValidateAntiForgeryToken
e depois substituí-lo pelos atributos IgnoreAntiforgeryToken
, pode ser usado o atributo AutoValidateAntiforgeryToken. Esse atributo funciona de forma idêntica ao atributo ValidateAntiForgeryToken
, exceto que ele não requer tokens para solicitações feitas usando os seguintes métodos HTTP:
- OBTER
- CABEÇA
- OPÇÕES
- RASTREIO
Recomendamos o uso de AutoValidateAntiforgeryToken
de forma ampla para cenários que não sejam de API. Esse atributo garante que as ações POST sejam protegidas por padrão. A alternativa é ignorar tokens de antifalsificação por padrão, a menos que ValidateAntiForgeryToken
seja aplicado a métodos individuais de ação. É 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 antifalsificação.
As APIs não têm um mecanismo automático para enviar a parte nãocookie 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 antifalsificação globais ou do controlador
O filtro IgnoreAntiforgeryToken é usado para eliminar a necessidade de um token de antifalsificação para determinada ação (ou controlador). Quando aplicado, este filtro substitui os filtros ValidateAntiForgeryToken
e AutoValidateAntiforgeryToken
especificados a um nível mais alto (globalmente ou num 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 após a autenticação do utilizador, redirecionando-o para uma vista ou página Razor Pages.
JavaScript, AJAX e SPAs
Em aplicativos tradicionais baseados em HTML, os tokens antifalsificação são passados para o servidor usando campos de formulário ocultos. Em aplicativos e SPAs modernos baseados em JavaScript, 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 os cookies forem usados para armazenar tokens de autenticação e autenticar solicitações de API no servidor, o CSRF é um problema 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 antifalsificação no cliente e enviar o token como um cabeçalho de solicitação é uma abordagem recomendada.
Javascript
Usando JavaScript com visualizações, o token pode ser criado usando um serviço de dentro da visualização. Injete o serviço de IAntiforgery na visualização e ligue para 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>
Esta abordagem elimina a necessidade de lidar diretamente com a configuração de cookies do servidor ou lê-los a partir do cliente.
O exemplo anterior usa JavaScript para ler o valor de campo oculto para o cabeçalho AJAX POST.
JavaScript também pode acessar tokens em cookies e usar o conteúdo do cookiepara 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 antifalsificação para procurar o cabeçalho X-CSRF-TOKEN
:
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
AngularJS usa uma convenção para abordar CSRF. Se o servidor envia um cookie com o nome XSRF-TOKEN
, o serviço $http
AngularJS adiciona o valor cookie a um cabeçalho quando envia uma solicitação ao servidor. Este processo é automático. O cliente não precisa definir o cabeçalho explicitamente. O nome do cabeçalho é X-XSRF-TOKEN
. O servidor deve detetar esse cabeçalho e validar seu conteúdo.
Para a API do ASP.NET Core funcionar com esta convenção ao iniciar a aplicação:
- Configure a sua aplicação para fornecer um token em um cookie definido como
XSRF-TOKEN
. - Configure o serviço antifalsificação para procurar um cabeçalho chamado
X-XSRF-TOKEN
, que é o nome de cabeçalho padrão da 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");
}
Observação
Quando o token antifalsificação é fornecido no cabeçalho da solicitação e na carga útil do formulário, somente o token no cabeçalho é validado.
Cookies de autenticação e antifalsificação do Windows
Ao utilizar a Autenticação do Windows, os endpoints da aplicação devem ser protegidos contra ataques CSRF da mesma forma que os cookies. O navegador envia implicitamente o contexto de autenticação para o servidor e, portanto, os endpoints devem ser protegidos contra ataques CSRF.
Estender a funcionalidade de antifalsificação
O tipo IAntiforgeryAdditionalDataProvider permite que os desenvolvedores estendam o comportamento do sistema anti-CSRF transferindo dados adicionais dentro de cada token. O método GetAdditionalData é chamado cada vez que um token de campo é gerado, e o valor de retorno é incorporado no token gerado. Um implementador pode retornar um carimbo de data/hora, um nonce ou qualquer outro valor e depois chamar ValidateAdditionalData para validar esses dados quando o token for validado. O nome de usuário do cliente já está incorporado nos tokens gerados, portanto, não há necessidade de incluir essas informações. Se um token incluir dados suplementares, mas nenhum IAntiForgeryAdditionalDataProvider
estiver configurado, os dados suplementares não serão validados.