Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Por Fiyaz Hasan y Rick Anderson
La falsificación de solicitud entre sitios es un ataque contra aplicaciones hospedadas en web, en el que una aplicación web malintencionada puede influir en la interacción entre un explorador cliente y una aplicación web que confía en ese explorador. Estos ataques son posibles porque los exploradores web envían automáticamente algunos tipos de token de autenticación con cada solicitud en un sitio web. Esta forma de exploit también se conoce como ataque con un clic o secuestro de sesión porque el ataque aprovecha la sesión autenticada previamente del usuario. La falsificación de solicitudes entre sitios también se conoce como XSRF o CSRF.
Ejemplo de un ataque de CSRF:
Un usuario inicia sesión en
www.good-banking-site.example.comcon la autenticación de formularios. El servidor autentica al usuario y emite una respuesta que incluye una autenticación cookie. El sitio es vulnerable a ataques porque confía en cualquier solicitud que reciba con una cookie de autenticación válida.El usuario visita un sitio malintencionado,
www.bad-crook-site.example.com.El sitio malintencionado,
www.bad-crook-site.example.com, contiene un formulario HTML similar al ejemplo siguiente:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.example.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 el
actiondel formulario publica en el sitio vulnerable, no en el sitio malintencionado. Esta es la parte "entre sitios" de CSRF.El usuario selecciona el botón Enviar. El explorador realiza la solicitud e incluye automáticamente la cookie de autenticación para el dominio solicitado,
www.good-banking-site.example.com.La solicitud se ejecuta en el servidor de
www.good-banking-site.example.comcon el contexto de autenticación del usuario y puede realizar cualquier acción que un usuario autenticado pueda realizar.
Además del escenario en el que el usuario selecciona el botón para enviar el formulario, el sitio malintencionado podría:
- Ejecutar un script que envíe automáticamente el formulario.
- Enviar el envío del formulario como una solicitud AJAX.
- Ocultar el formulario mediante CSS.
Estos escenarios alternativos no requieren ninguna acción ni entrada por parte del usuario aparte de visitar inicialmente el sitio malintencionado.
El uso de HTTPS no impide un ataque de CSRF. El sitio malintencionado puede enviar https://www.good-banking-site.example.com/ una solicitud tan fácilmente como puede enviar una solicitud no segura.
Algunos ataques se dirigen a puntos de conexión que responden a solicitudes GET, en cuyo caso se puede usar una etiqueta de imagen para realizar la acción. Esta forma de ataque es común en sitios de foros que permiten imágenes pero bloquean JavaScript. Las aplicaciones que cambian el estado de las solicitudes GET, en las que se modifican variables o recursos, son vulnerables a ataques malintencionados. Las solicitudes GET que cambian de estado no son seguras. Un procedimiento recomendado es no cambiar nunca el estado en una solicitud GET.
Los ataques de CSRF se pueden producir en las aplicaciones web que usan cookies para la autenticación porque:
- Los exploradores almacenan cookies emitidas por una aplicación web.
- Las cookies almacenadas incluyen cookies de sesión para los usuarios autenticados.
- Los exploradores envían todas las cookies asociadas con un dominio a la aplicación web en cada solicitud independientemente de cómo se generó la solicitud a la aplicación en el explorador.
Sin embargo, los ataques CSRF no se limitan a aprovechar las vulnerabilidades de las cookies. Por ejemplo, la autenticación básica y Digest también son vulnerables. Una vez que un usuario inicia sesión con la autenticación básica o implícita, el explorador envía automáticamente las credenciales hasta que finaliza la sesión.
En este contexto, la sesión hace referencia a la sesión del lado cliente durante la cual se autentica el usuario. No está relacionado con las sesiones del servidor ni con el middleware de sesión de ASP.NET Core.
Para protegerse contra las vulnerabilidades de CSRF, los usuarios pueden tomar precauciones:
- Cierre la sesión de las aplicaciones web cuando termine de usarlas.
- Borra periódicamente las cookies del explorador.
Sin embargo, las vulnerabilidades de CSRF son fundamentalmente un problema con la aplicación web, no con el usuario final.
Aspectos básicos de la autenticación
La autenticación basada en Cookie es una forma popular de autenticación. Los sistemas de autenticación basados en tokens están creciendo en popularidad, especialmente para aplicaciones de página única (SPA).
Autenticación basada en Cookie
Cuando un usuario se autentica con su nombre de usuario y contraseña, se emite un token que contiene un vale de autenticación. El token se puede usar para la autenticación y autorización. El token se almacena como una cookie que se envía con cada solicitud que realiza el cliente. La generación y validación de este cookie se realiza con el middleware de autenticación cookie. El middleware serializa una entidad de seguridad de usuario en una cookie cifrada. En las solicitudes posteriores, el middleware valida la cookie, vuelve a crear la entidad de seguridad y asigna la entidad de seguridad a la propiedad HttpContext.User.
Autenticación basada en tokens
Cuando se autentica un usuario, se emite un token (no un token de antifalsificación). El token contiene información de usuario en forma de notificaciones o un token de referencia que apunta la aplicación al estado de usuario mantenido en la aplicación. Cuando un usuario intenta acceder a un recurso que requiere autenticación, el token se envía a la aplicación con un encabezado de autorización adicional en forma de token de portador. Este enfoque hace que la aplicación no tenga estado. En cada solicitud posterior, el token se pasa en la solicitud de validación del lado servidor. Este token no está cifrado; está codificado. En el servidor, el token se descodifica para acceder a su información. Para enviar el token en solicitudes posteriores, almacene el token en el almacenamiento local del explorador. Colocar un token en el almacenamiento local del explorador, recuperarlo y usarlo como token de portador proporciona protección contra ataques de CSRF. Sin embargo, si la aplicación es vulnerable a la inserción de scripts a través de XSS o un archivo javascript externo en peligro, un ciberdelincuente podría recuperar cualquier valor del almacenamiento local y enviárselo a sí mismo. ASP.NET Core codifica todas las salidas del lado servidor de las variables de forma predeterminada, lo que reduce el riesgo de XSS. Si invalida este comportamiento mediante Html.Raw o código personalizado con entradas que no son de confianza, puede aumentar el riesgo de XSS.
No se preocupe por la vulnerabilidad de CSRF si el token se almacena en el almacenamiento local del explorador. La CSRF es un problema cuando el token se almacena en una cookie. Para obtener más información, consulta el problema de GitHub El ejemplo de código SPA agrega dos cookies.
Varias aplicaciones hospedadas en un dominio
Los entornos de hospedaje compartidos son vulnerables al secuestro de sesión, a la CSRF de inicio de sesión y a otros ataques.
Aunque example1.contoso.net y example2.contoso.net son hosts diferentes, hay una relación de confianza implícita entre los hosts bajo el dominio *.contoso.net. Esta relación de confianza implícita permite que hosts que podrían no ser de confianza afecten a las cookies de otros hosts (las directivas de mismo origen que rigen las solicitudes AJAX no se aplican necesariamente a las cookies HTTP).
Los ataques que aprovechan las cookies de confianza entre aplicaciones hospedadas en el mismo dominio pueden evitarse si no se comparten dominios. Cuando cada aplicación se hospeda en su propio dominio, no hay ninguna relación de confianza implícita que se pueda aprovechar.
Captura de encabezados de metadatos
Los exploradores modernos adjuntan encabezados de solicitud Fetch Metadata (lo que es más importante) Sec-Fetch-Sitea cada solicitud.
Sec-Fetch-Site describe la relación entre el origen que inició la solicitud y el origen solicitado: same-origin identifica una solicitud que el sitio se hizo a sí mismo, mientras que same-site y cross-site identifican solicitudes iniciadas por otro origen. La cabecera Origin incluye el origen iniciador y sirve como alternativa para los navegadores anteriores a Fetch Metadata.
Sec-Fetch-Site y Origin están prohibidos los encabezados de solicitud: el explorador los establece y JavaScript que se ejecuta en una página no puede invalidarlos ni falsificarlos. Eso los convierte en una señal fiable para distinguir las solicitudes propias de un sitio de las solicitudes entre sitios sin necesidad de un token emitido por el servidor. La protección CSRF automática integrada en ASP.NET Core usa esta señal para rechazar publicaciones de formulario entre sitios que no son de confianza explícita.
Protección CSRF automática en ASP.NET Core
ASP.NET Core incluye un middleware de protección CSRF automático que está habilitado de forma predeterminada en las aplicaciones compiladas con WebApplication.CreateBuilder. A diferencia del sistema antiforgery basado en tokens, este middleware no emite ni valida tokens. En su lugar, inspecciona las Sec-Fetch-Site y Origincabeceras de metadatos de obtención y registra un veredicto de validación sobre la solicitud. Los componentes que procesan los datos de formulario enviados aplican ese veredicto, rechazando publicaciones de formulario entre orígenes que no son de confianza explícita.
Para la mayoría de las aplicaciones, no se requieren cambios de código: las solicitudes del navegador del mismo origen, los métodos HTTP seguros y los clientes que no son navegadores (curl, de servidor a servidor y aplicaciones móviles) siguen funcionando sin verse afectados. El middleware afecta principalmente a las aplicaciones que aceptan publicaciones de formularios entre orígenes desde un explorador, como un sitio que publica un formulario en una API en un origen diferente. Estos escenarios deben configurar CORS para declarar el origen de confianza o excluir el punto de conexión.
Este middleware es adicional al sistema de protección antifalsificación basado en tokens. Las dos protecciones coexisten y pueden estar activas en el mismo punto de conexión. Para obtener una comparación de cuándo se aplica cada una de ellas, consulte Interacción con la antiforgería basada en tokens.
Cómo funciona
Para cada solicitud, el middleware evalúa una breve cadena de reglas para alcanzar un veredicto, permitido o denegado. Las comprobaciones se ejecutan en orden y la primera coincidencia gana:
-
Los métodos HTTP seguros siempre se permiten.
GET,HEAD,OPTIONSyTRACElas solicitudes pasan a través. Esto sigue lo indicado en RFC 9110 §9.2.1 y es coherente con la regla consolidada desde hace tiempo de que los extremos no deben cambiar de estado conGET. - Se permite
Sec-Fetch-Site: same-originoSec-Fetch-Site: none. Los exploradores modernos envíanSec-Fetch-Siteen cada solicitud.same-origincubre la navegación normal en la aplicación y la captura, ynonecubre las solicitudes iniciadas directamente por el usuario (escribiendo una dirección URL mediante un marcador). Esta es la ruta de acceso de código más común: la mayoría del tráfico legítimo del explorador sale aquí. - Se permite un origen de confianza de CORS. Si la solicitud incluye la cabecera
Originy la directiva CORS resuelta para el punto de conexión confía en ese origen, se permite la solicitud. El middleware determina la directiva de la misma forma que el middleware de CORS: primero, la directiva por punto de conexión de[EnableCors("name")]y, después, la directiva predeterminada registrada conAddDefaultPolicy. Consulte Permitir clientes de distintos orígenes para obtener información sobre los límites importantes de esta regla. - Se deniega cualquier otro
Sec-Fetch-Sitevalor. CuandoSec-Fetch-Siteescross-siteosame-sitey el origen no es de confianza a través de CORS, se deniega la solicitud. -
No hay
Sec-Fetch-Site, peroOriginestá presente: el middleware comparaOriginconscheme://host[:port]construido a partir de la solicitud. Si coinciden, se permite la solicitud; de lo contrario, se deniega. Esta es la ruta alternativa para navegadores anteriores a la especificación Fetch Metadata (publicada hacia 2020). - No
Sec-Fetch-Sitey noOrigin: se permite la solicitud. Los exploradores siempre envían al menos uno de estos en una solicitud de escritura, por lo que una solicitud que falta es casi seguramente un cliente que no es de explorador, comocurl, Postman, una aplicación móvil o un llamador de servidor a servidor. CSRF es un vector de ataque de solo explorador, por lo que estas solicitudes pasan a través.
El middleware registra este veredicto sobre la solicitud en lugar de finalizar la propia solicitud. Para saber cómo y cuándo un veredicto denegado se convierte en una respuesta HTTP 400 Bad Request , consulte Validación diferida.
Validación diferida
El middleware no rechaza una solicitud por sí sola. En su lugar, registra su veredicto en la solicitud IAntiforgeryValidationFeature(la misma característica que usa el sistema antiforgery basado en tokens), donde se registra un veredicto denegado como no válido. La solicitud continúa hacia abajo en la canalización. Un veredicto no válido se convierte en un HTTP 400 Bad Request solo cuando un componente que procesa los datos del formulario lo observa. Este aplazamiento coincide con el comportamiento del sistema basado en tokens: el veredicto se genera al principio, pero se aplica en el punto en el que se consume un formulario.
Los siguientes componentes leen IAntiforgeryValidationFeature y rechazan una solicitud con 400 - Bad Request cuando el veredicto registrado no es válido:
- Acciones de MVC protegidas por antiforgería.
- Puntos de conexión de API mínimos que enlazan un parámetro de formulario.
- Blazor Puntos de conexión de SSR.
- Cualquier código que lea el formulario de solicitud directamente, que actúa como un backstop.
Cada consumidor confirma primero que un middleware de protección antifalsificación o contra CSRF realmente se ejecutó antes de confiar en el veredicto, por lo que una canalización sin ninguno de los dos middleware no produce falsos rechazos.
Una consecuencia de este modelo es que un punto de conexión que nunca lee datos de formulario se ejecuta incluso cuando el veredicto no es válido. Por ejemplo, un punto de conexión de API JSON que enlaza su cuerpo desde JSON o un controlador que omite el cuerpo de la solicitud no se rechaza automáticamente en una solicitud entre orígenes. El veredicto todavía está registrado en IAntiforgeryValidationFeature para el código que quiere inspeccionarlo, pero nada lo exige. CSRF es un vector de ataque basado en formularios y cookie, por lo que los endpoints que no procesan formularios enviados por el navegador generalmente no necesitan este tipo de rechazo. Los puntos de conexión que sí procesan formularios—Razor páginas, vistas MVC, Blazor SSR y enlace de formularios de Minimal API—obtienen la protección automáticamente.
Comportamiento predeterminado
El middleware se registra automáticamente por WebApplication.CreateBuilder y se ejecuta después de la autenticación y la autorización. Valida cada solicitud mediante la implementación registrada ICsrfProtection , que de forma predeterminada aplica las reglas descritas en Funcionamiento. La implementación predeterminada se puede reemplazar; consulte Personalización: implementar ICsrfProtection. Para desactivar completamente el middleware, consulte Deshabilitación global.
El resultado es que una aplicación mínima con un punto de conexión para procesar formularios como el siguiente ya está protegida:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapPost("/widgets", ([FromForm] Widget w) =>
Results.Created($"/widgets/{w.Id}", w));
app.Run();
Un explorador que realiza una solicitud de mismo origen POST /widgets alcanza el punto de conexión normalmente. Un navegador en https://attacker.example.com, al enviar el mismo formulario, se rechaza con 400 - Bad Request cuando el endpoint vincula el formulario, antes de que se ejecute el cuerpo del controlador. Se permite una curl solicitud sin Sec-Fetch-Site o Origin .
Dado que el rechazo se pospone a los componentes que consumen formularios, un endpoint que no lee datos de formulario —como una API JSON que vincula el cuerpo a partir de JSON— no se rechaza automáticamente, ni siquiera en una solicitud de origen cruzado. El veredicto todavía se registra en la solicitud de código que quiere inspeccionarlo.
El middleware se integra con el modelo antifalsificación existente:
-
API minimalistas: Llamar a
.DisableAntiforgery()en un punto de conexión excluye a ese punto de conexión de ambos: el middleware basado en tokens y el middleware de protección CSRF. Ambos comprueban los mismos metadatos (IAntiforgeryMetadata { RequiresValidation = false }). -
Controladores y acciones de MVC:
[IgnoreAntiforgeryToken]también excluye el punto de conexión de ambas protecciones.
Permitir clientes de origen cruzado
El escenario más común que requiere acción es un cliente basado en navegador que envía un formulario de origen cruzado; por ejemplo, un sitio en https://app.contoso.com que envía un formulario a una API en https://api.contoso.com. Estos envíos de formulario se deniegan de forma predeterminada porque Sec-Fetch-Site es same-site o cross-site en lugar de same-origin, y el consumidor del formulario aplica ese veredicto con un 400 - Bad Request.
El middleware CSRF no presenta su propia lista de confianza. Reutiliza la misma directiva CORS que el CORS middleware resuelve para el extremo: si esa directiva permite el/la Origin de la solicitud, el middleware de CSRF registra un veredicto favorable para la solicitud.
La directiva se elige para cada punto de conexión en este orden:
-
[EnableCors("api")](MVC) o.RequireCors("api")(API mínima) → la política con nombre"api". - No hay metadatos de CORS en el punto de conexión → la directiva predeterminada registrada con
AddDefaultPolicy. - Ninguna directiva coincidente (directiva con nombre no registrada, ninguna directiva predeterminada o
services.AddCors()nunca llamada) → ninguna confianza derivada de CORS. El middleware recurre a las reglasSec-Fetch-Sitey de Origin-vs-Host.
Un ejemplo mínimo con una política predeterminada y un punto de conexión de una API mínima:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
policy.WithOrigins("https://app.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod());
});
var app = builder.Build();
app.UseCors();
app.MapPost("/widgets", ([FromForm] Widget w) =>
Results.Created($"/widgets/{w.Id}", w));
app.Run();
Para una directiva con nombre específico para un único punto de conexión:
app.MapPost("/widgets", ([FromForm] Widget w) => Results.Created($"/widgets/{w.Id}", w))
.RequireCors("api");
Advertencia
AllowAnyOrigin intencionadamente no se considera una señal de confianza para CSRF.
AllowAnyOrigin significa «cualquier navegador puede leer este recurso», lo cual es una cuestión distinta de «cualquier origen puede modificar el estado en nombre del usuario». Tratar AllowAnyOrigin como de confianza convertiría este middleware en una operación nula para las escrituras de origen cruzado. Las aplicaciones que necesiten una política CORS de acceso de lectura público combinada con operaciones de escritura protegidas frente a CSRF deben enumerar explícitamente los orígenes de escritura de confianza con WithOrigins o excluir los extremos de escritura si no dependen de la autenticación basada en cookie.
[DisableCors] en un punto de conexión no es una excepción de CSRF. Omite el paso de confianza derivado de CORS, y la solicitud debe seguir cumpliendo Sec-Fetch-Site y las reglas de Origin frente a Host. Para excluir un extremo de la protección contra CSRF, consulte Excluir un extremo.
Para obtener más información sobre cómo configurar CORS en sí(AddCors , AddDefaultPolicyAddPolicy, WithOriginsy el resto de la API del generador de directivas), consulte Habilitación de solicitudes entre orígenes (CORS) en ASP.NET Core.
Excluir un extremo
Si un extremo no es accesible desde el navegador o está protegido por un mecanismo distinto de cookie, como un token bearer o una clave de API, exclúyalo individualmente en lugar de deshabilitar el middleware de forma global.
API minimalistas — llame a DisableAntiforgery en el endpoint o grupo:
app.MapPost("/api/webhook", (WebhookPayload p) => Results.Accepted())
.DisableAntiforgery();
Controladores MVC : se aplican [IgnoreAntiforgeryToken] a la acción o al controlador:
[ApiController]
[Route("api/[controller]")]
[IgnoreAntiforgeryToken]
public class WebhookController : ControllerBase
{
[HttpPost]
public IActionResult Post([FromBody] WebhookPayload payload) => Accepted();
}
Cualquiera de los dos enfoques añade IAntiforgeryMetadata { RequiresValidation = false } al endpoint, que el middleware de CSRF respeta al omitir la validación.
Advertencia
La deshabilitación de la protección CSRF en un punto de conexión solo debe realizarse cuando el punto de conexión no es vulnerable a ataques CSRF, por ejemplo, puntos de conexión que no se pueden llamar desde un explorador o que están protegidos con autenticación nocookie autenticada, como tokens de portador o claves de API. No deshabilite la protección CSRF en puntos de conexión accesibles para el explorador que dependen de cookies para la autenticación.
Deshabilitar globalmente
El middleware se puede deshabilitar en toda la aplicación mediante la clave de DisableCsrfProtection configuración. Esto es una vía de escape; es preferible usar exclusiones por endpoint.
En appsettings.json:
{
"DisableCsrfProtection": true
}
O como una variable de entorno:
ASPNETCORE_DisableCsrfProtection=true
Cuando esta clave se establece en true, WebApplication omite registrar el middleware en la pipeline. El ICsrfProtection servicio permanece registrado, por lo que todo lo que lo resuelva continúa funcionando directamente.
Advertencia
El middleware CSRF automático también satisface el requisito de antiforgería para los puntos de conexión que requieren validación, incluso cuando una aplicación no llama a app.UseAntiforgery(). Si una aplicación depende de la protección antifalsificación pero no llama a app.UseAntiforgery(), deshabilitar globalmente el middleware de CSRF o ejecutar la aplicación en un host que no se ha compilado con WebApplication, donde no se agrega el middleware, deja esos puntos de conexión sin middleware de protección antifalsificación. Después, una solicitud a este punto de conexión produce una excepción. Llame a app.UseAntiforgery() en esa configuración.
Compatibilidad con navegadores
Sec-Fetch-Site es compatible con todas las versiones actuales de los exploradores basados en Chromium, Firefox y Safari. Para obtener una tabla de compatibilidad autoritativa, consulte la referencia de MDN para Sec-Fetch-Site.
Los navegadores más antiguos, anteriores a Fetch Metadata, no envían Sec-Fetch-Site. Para esos clientes, el middleware recurre a comparar el encabezado Origin con el esquema y el host de la solicitud. Los navegadores han enviado Origin en solicitudes de escritura de origen cruzado durante muchos años, por lo que este mecanismo alternativo cubre prácticamente todo el tráfico de navegadores heredados.
Clientes que no son navegadores—curl, Postman, aplicaciones móviles, clientes de servidor a servidor—normalmente no envían ni Sec-Fetch-Site ni Origin. Estas solicitudes se permiten porque CSRF es un vector de ataque de solo explorador que depende del explorador adjuntando automáticamente credenciales ambientales como cookies. Un cliente que no es de explorador que quiere atacar la API no tiene necesidad de CSRF; simplemente puede llamar a la API directamente con las credenciales que posee.
Personalización: implementar ICsrfProtection
La lógica de decisión está encapsulada tras una interfaz con un único método:
namespace Microsoft.AspNetCore.Antiforgery;
public interface ICsrfProtection
{
ValueTask<CsrfProtectionResult> ValidateAsync(HttpContext context);
}
Para reemplazar la implementación predeterminada, registre un singleton en la inserción de dependencias. Dado que el marco usa TryAddSingleton, una llamada explícita AddSingleton invalida el valor predeterminado:
builder.Services.AddSingleton<ICsrfProtection, AllowlistCsrfProtection>();
Una implementación personalizada es útil cuando el modelo de confianza no se ajusta a CORS( por ejemplo, cuando se prefiere una lista de permitidos fija de orígenes de asociados o cuando se necesitan reglas más estrictas:
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Http;
public sealed class AllowlistCsrfProtection : ICsrfProtection
{
private static readonly HashSet<string> SafeMethods =
new(StringComparer.OrdinalIgnoreCase) { "GET", "HEAD", "OPTIONS", "TRACE" };
private static readonly HashSet<string> TrustedOrigins =
new(StringComparer.OrdinalIgnoreCase)
{
"https://app.contoso.com",
"https://admin.contoso.com",
};
public ValueTask<CsrfProtectionResult> ValidateAsync(HttpContext context)
{
if (SafeMethods.Contains(context.Request.Method))
{
return ValueTask.FromResult(CsrfProtectionResult.Allowed());
}
var origin = context.Request.Headers.Origin.ToString();
var allowed = !string.IsNullOrEmpty(origin) && TrustedOrigins.Contains(origin);
return ValueTask.FromResult(
allowed ? CsrfProtectionResult.Allowed() : CsrfProtectionResult.Denied());
}
}
El middleware sigue respetando .DisableAntiforgery() / [IgnoreAntiforgeryToken] independientemente de qué implementación esté registrada; la exclusión la gestiona el propio middleware antes de que se llame a ValidateAsync.
Interacción con la antiforgería basada en tokens
Las dos defensas CSRF tienen como destino diferentes capas y están diseñadas para coexistir. También comparten la misma característica de solicitud: ambos registran su resultado en IAntiforgeryValidationFeaturey los consumidores de formularios aplican cualquier veredicto que esté presente.
| Aspecto | Basado en tokens AntiforgeryMiddleware |
Software intermedio de protección automática contra CSRF |
|---|---|---|
| Introducido | ASP.NET Core 2.0+ | .NET 11 |
| Activation | Suscribirse a través de app.UseAntiforgery() (o de forma implícita mediante AddMvc / MapRazorPages / AddRazorComponents) |
Insertado automáticamente por WebApplication.CreateBuilder |
| Valida | Token sincronizado (campo de formulario + cookie par) |
Sec-Fetch-Site
/
Origin encabezados |
| Requires | Información general sobre la protección de datos de ASP.NET Core para el cifrado de tokens | Sin tokens, sin estado |
| Ámbito del navegador | Todos los exploradores que envían cookies | Todos los navegadores modernos; Origin alternativa para sistemas heredados |
| Exclusión voluntaria por punto de conexión | .DisableAntiforgery() / [IgnoreAntiforgeryToken] |
Igual: ambos respetan los mismos metadatos |
El middleware basado en tokens protege específicamente contra el patrón de ataque CSRF clásico en el que un sitio malintencionado desencadena un formulario POST en un sitio vulnerable mediante las cookies ambientales del usuario. El middleware CSRF automático aborda la misma amenaza en la capa HTTP mediante metadatos proporcionados por el explorador. Ambos pueden estar activos en el mismo punto de conexión y muchas aplicaciones se beneficiarán de la defensa en profundidad:
- Razor Las aplicaciones de Páginas, MVC y Blazor SSR que ya usan el sistema de tokens obtienen una comprobación basada en la cabecera que se ejecuta antes de la validación de los tokens, sin alterar el flujo de los tokens.
-
Las aplicaciones de API mínimas que enlazan datos de formularios obtienen un valor predeterminado útil sin necesidad de llamar a
app.UseAntiforgery()o pasarIAntiforgerya través de los puntos de conexión. - Las API llamadas desde SPA de origen distinto pueden utilizar este middleware combinado con una lista de orígenes permitidos de CORS y prescindir por completo del sistema de tokens si la API nunca sirve formularios HTML.
El middleware automático de CSRF reemplaza el sistema de tokens en muchos casos, ya que ambos protegen los mismos endpoints que gestionan formularios. Mantenga el sistema basado en tokens cuando:
- La aplicación debe admitir exploradores que no envíen
Sec-Fetch-Site. Consulte Compatibilidad con el explorador. - La aplicación usa IAntiforgeryAdditionalDataProvider para realizar un recorrido de ida y vuelta datos adicionales dentro del token.
- Un requisito de cumplimiento o revisión de seguridad especifica la defensa de tokens como una capa independiente.
Para más información sobre el sistema basado en tokens, incluida la integración de formularios, los flujos AJAX y la configuración mediante las API AntiforgeryOptions y IAntiforgery, consulte Protección antifalsificación en ASP.NET Core.
La validación de tokens tiene prioridad
Cuando una aplicación llama a app.UseAntiforgery(), el middleware basado en tokens se ejecuta después del middleware automático de CSRF. El middleware de token borra cualquier veredicto que el middleware CSRF registró y lo reemplaza por el resultado de la validación del token. El resultado del token es autoritativo:
- Una solicitud que el middleware CSRF marcó como no válida se vuelve válida si incluye un token válido.
- Una solicitud que el middleware CSRF ha permitido se marca como no válida si su token falta o no es válido.
Este orden significa que las aplicaciones que usan el sistema de tokens mantienen el mismo comportamiento de extremo a extremo que tenían antes de que existiera el middleware automático, mientras que las aplicaciones que no usan tokens quedan sujetas al dictamen del middleware de CSRF.
Blazor representación estática del lado servidor
Blazor los extremos estáticos de renderizado del lado del servidor (SSR) participan en el mismo modelo diferido. El extremo Razor Components confía en el veredicto registrado en IAntiforgeryValidationFeature por el middleware anterior y devuelve 400 - Bad Request para una solicitud POST de formulario solo cuando ese veredicto es inválido. El punto de conexión ya no valida la propia solicitud.
El comportamiento depende del middleware que se ejecutó:
- Las aplicaciones que llaman
app.UseAntiforgery()no se modifican. El middleware basado en tokens valida cada solicitud, y se generan tokens antifalsificación para los formularios renderizados, igual que antes. - En su lugar, las aplicaciones que no llaman
app.UseAntiforgery()están protegidas por el middleware CSRF automático. En esa configuración, el punto de conexión omite la generación de tokens antiforgery porque ningún middleware de token está presente para validar un token en una solicitud posterior.
Se trata de un cambio de comportamiento en el SSR estático para los casos que antes eliminaban app.UseAntiforgery(): ahora quedan protegidos por el middleware de CSRF en lugar de quedar sin protección, y dejan de emitir tokens antifalsificación. Para obtener instrucciones sobre la migración, consulte Migración de ASP.NET Core de .NET 10 a ASP.NET Core en .NET 11. Para obtener el aviso formal de cambio importante, consulte Blazor representación del lado servidor aplaza la validación antiforgería al middleware.
Troubleshooting
Síntoma: Las solicitudes del mismo origen desde un navegador se realizan correctamente, pero los envíos de formularios entre orígenes devuelven 400 - Bad Request sin cuerpo.
Causa: El middleware de CSRF registró una evaluación no válida para la solicitud de origen cruzado, y un componente de procesamiento de formularios —como una acción de MVC, un enlace de formularios de una API mínima o un envío de formularios SSR Blazor— hizo cumplir esa evaluación mediante un 400 - Bad Request. Este es el comportamiento predeterminado esperado para los puntos de conexión que procesan formularios.
Resolución: Elija una de las siguientes opciones, en función del escenario:
- Si el origen de la llamada es conocido y de confianza, permitalo a través de CORS.
- Si el punto de conexión no es accesible desde el navegador o usa autenticación no cookie, exclúyalo con
.DisableAntiforgery()o[IgnoreAntiforgeryToken]. - Si toda la aplicación debe rechazarse (por ejemplo, durante una ventana de migración), deshabilite globalmente.
Diagnóstico de problemas: El middleware registra todos los veredictos inválidos en el nivel Debug, en la categoría Microsoft.AspNetCore.Antiforgery.CsrfProtectionMiddleware, con el nombre de evento CsrfValidationFailed. Habilite el registro Debug para esa categoría en appsettings.Development.json:
{
"Logging": {
"LogLevel": {
"Microsoft.AspNetCore.Antiforgery.CsrfProtectionMiddleware": "Debug"
}
}
}
A continuación, aparece un veredicto grabado en el registro como:
dbug: Microsoft.AspNetCore.Antiforgery.CsrfProtectionMiddleware[1]
Cross-origin CSRF protection marked request POST /widgets from origin 'https://attacker.example.com' as invalid.
Reproducir localmente: Utilice curl con un encabezado Origin explícito para simular una solicitud del navegador entre orígenes contra un punto de conexión de formulario:
curl -i -X POST https://localhost:{PORT}/widgets \
-H "Origin: https://attacker.example.com" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "name=test"
Reemplace por {PORT} el puerto HTTPS local de la aplicación. Se observa 400 - Bad Request porque el extremo vincula el formulario, lo que aplica el veredicto registrado. Un extremo que no es de formulario devuelve su respuesta normal porque nada lee el resultado. Sin el encabezado Origin, se permite la misma solicitud porque curl tampoco envía Sec-Fetch-Site, y una solicitud sin ninguno de los dos encabezados se considera de un cliente no navegador.
El sistema antiforgería basado en tokens descrito en el resto de este artículo predescribe este middleware y permanece disponible. Para la mayoría de las aplicaciones, la protección automática es suficiente por sí sola. Para obtener instrucciones sobre cuándo mantener el sistema basado en tokens y cómo migrar, consulte Migración de ASP.NET Core de .NET 10 a ASP.NET Core en .NET 11.
Antifalsificación en ASP.NET Core
Advertencia
ASP.NET Core implementa la antifalsificación mediante la Protección de datos de ASP.NET Core. La pila de protección de datos debe configurarse para que funcione en una granja de servidores. Para obtener más información, consulte Configuración de la protección de datos.
El middleware de antifalsificación se agrega al contenedor de inserción de dependencias cuando se llama a una de las siguientes API en Program.cs:
Para más información, consulte Antifalsificación con API mínima.
El elemento FormTagHelper inserta tokens antifalsificación en los elementos de formulario HTML. El siguiente marcado en un archivo de Razor genera automáticamente tokens de antifalsificación:
<form method="post">
<!-- ... -->
</form>
De forma similar, IHtmlHelper.BeginForm genera tokens antifalsificación de forma predeterminada si el método del formulario no es GET.
La generación automática de tokens de antifalsificación para elementos de formulario HTML se produce cuando la etiqueta <form> contiene el atributo method="post" y se cumple alguna de las siguientes condiciones:
- El atributo action está vacío (
action=""). - El atributo action no se proporciona (
<form method="post">).
La generación automática de tokens de antifalsificación para elementos de formulario HTML se puede deshabilitar:
Deshabilite explícitamente los tokens de antifalsificación con el atributo
asp-antiforgery.<form method="post" asp-antiforgery="false"> <!-- ... --> </form>El elemento de formulario se ha excluido de los asistentes de etiquetas mediante el símbolo de rechazo ! del asistente de etiquetas:
<!form method="post"> <!-- ... --> </!form>Quite
FormTagHelperde la vista.FormTagHelperpuede eliminarse de una vista mediante la adición de la siguiente directiva a la vista Razor.@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Nota:
Las Razor páginas están protegidas automáticamente contra XSRF/CSRF. Para obtener más información, vea XSRF/CSRF y Razor Pages.
El enfoque más común para defenderse contra ataques de CSRF es usar el patrón de token del sincronizador (STP). El STP se usa cuando el usuario solicita una página con datos de formulario:
- El servidor envía un token asociado a la identidad del usuario actual al cliente.
- El cliente devuelve el token al servidor para su comprobación.
- Si el servidor recibe un token que no coincide con la identidad del usuario autenticado, se rechaza la solicitud.
El token es único e imprevisible. El token también se puede usar para garantizar la secuenciación correcta de una serie de solicitudes (por ejemplo, garantizar la secuencia de solicitudes de: página 1 > página 2 > página 3). Todos los formularios de las plantillas de Razor Pages y de ASP.NET Core MVC generan tokens de antifalsificación. El siguiente par de ejemplos de vista genera tokens de antifalsificación:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Agregue explícitamente un token de antifalsificación a un elemento <form> sin usar asistentes de etiquetas con el asistente de HTML @Html.AntiForgeryToken:
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
En cada uno de los casos anteriores, ASP.NET Core agrega un campo de formulario oculto similar al ejemplo siguiente:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core incluye tres filtros para trabajar con tokens de antifalsificación:
Antifraude con AddControllers
La llamada a AddControllersno habilita tokens de antifalsificación. Se debe llamar a AddControllersWithViews para tener compatibilidad integrada con tokens de antifalsificación.
Varias pestañas del explorador y el patrón de token del sincronizador
No se admiten varias pestañas que inicien sesión como usuarios diferentes, o una que inicie sesión como anónima.
Configurar el sistema antifalsificación con AntiforgeryOptions
Personalice AntiforgeryOptions en el archivo Program de la aplicación.
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties†.
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Establezca las propiedades de la cookie de antifalsificación mediante las propiedades de la clase CookieBuilder, como se muestra en la tabla siguiente.
| Opción | Descripción |
|---|---|
| Cookie | Determina la configuración usada para crear las cookies de antifalsificación. |
| FormFieldName | Nombre del campo de formulario oculto utilizado por el sistema de antifalsificación para representar tokens de antifalsificación en vistas. |
| HeaderName | Nombre del encabezado utilizado por el sistema de antifalsificación. Si es null, el sistema solo tiene en cuenta los datos del formulario. |
| SuppressXFrameOptionsHeader | Especifica si se va a suprimir la generación del encabezado X-Frame-Options. De forma predeterminada, el encabezado se genera con un valor de "SAMEORIGIN". Tiene como valor predeterminado false. |
Algunos exploradores no permiten que los puntos de conexión inseguros establezcan cookies con una marca "segura" o sobrescribir cookies cuya marca "segura" está establecida (para obtener más información, consulte Desuso de la modificación de cookies "seguras" de orígenes no seguros). Dado que la combinación de puntos de conexión seguros e inseguros es un escenario común en las aplicaciones, ASP.NET Core relaja la restricción de la directiva segura en algunas cookies, como la antifalsificación cookie, estableciendo el cookie de SecurePolicy en CookieSecurePolicy.None. Incluso si un usuario malintencionado roba un elemento de antifalsificación cookie, también debe robar el token de antifalsificación que normalmente se envía a través de un campo de formulario (más común) o de un encabezado de solicitud independiente (menos común), además de la autenticación cookie. Las cookies relacionadas con la autenticación o autorización usan una directiva más fuerte que CookieSecurePolicy.None.
Opcionalmente, puede proteger la protección contra falsificación cookie en entornos que no sean Development utilizando Capa de Conexión Segura (SSL), a través solo de HTTPS, estableciendo la siguiente propiedad AntiforgeryOptions.Cookie en el archivo de la aplicación Program.
if (!builder.Environment.IsDevelopment())
{
builder.Services.AddAntiforgery(o =>
{
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
}
Para obtener más información, vea CookieAuthenticationOptions.
Generación de tokens de antifalsificación con IAntiforgery
IAntiforgeryproporciona la API para configurar características de antifalsificación.
IAntiforgery se puede solicitar en Program.cs mediante WebApplication.Services. En el ejemplo siguiente se usa middleware desde la página principal de la aplicación para generar un token de antiforgería y enviarlo en la respuesta como un 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);
});
En el ejemplo anterior se establece una cookie denominada XSRF-TOKEN. El cliente puede leer esta cookie y proporcionar su valor como un encabezado adjunto a las solicitudes de AJAX. Por ejemplo, Angular incluye protección integrada contra XSRF que lee una cookie denominada XSRF-TOKEN de forma predeterminada.
Requerir validación de antifalsificación
El filtro de acción ValidateAntiForgeryToken se puede aplicar a una acción individual, un controlador o globalmente. Las solicitudes realizadas a las acciones que tienen aplicado este filtro se bloquean a menos que la solicitud incluya un token de antifalsificación válido:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
El atributo ValidateAntiForgeryToken requiere un token para las solicitudes a los métodos de acción que marca, incluidas las solicitudes HTTP GET. Si el atributo ValidateAntiForgeryToken se aplica en los controladores de la aplicación, se puede invalidar con el atributo IgnoreAntiforgeryToken.
Validar automáticamente tokens de antifalsificación solo para métodos HTTP no seguros
En lugar de aplicar ampliamente el atributo ValidateAntiForgeryToken y, a continuación, reemplazarlo con atributos IgnoreAntiforgeryToken, se puede usar el atributo AutoValidateAntiforgeryToken. Este atributo funciona de forma idéntica al atributo ValidateAntiForgeryToken, salvo que no requiere tokens para las solicitudes realizadas mediante los siguientes métodos HTTP:
- GET
- HEAD
- Opciones
- TRACE
Se recomienda usar ampliamente AutoValidateAntiforgeryToken para escenarios que no son de API. Este atributo garantiza que las acciones POST estén protegidas de forma predeterminada. La alternativa es omitir los tokens de antifalsificación de forma predeterminada, a menos que ValidateAntiForgeryToken se aplique a métodos de acción individuales. Es más probable que en este escenario un método de acción POST se deje desprotegido por error, lo que hace que la aplicación sea vulnerable a los ataques de CSRF. Todos los POST deben enviar el token de antifalsificación.
Las API no tienen un mecanismo automático para enviar la parte del token que no es una cookie. La implementación probablemente depende de la implementación del código de cliente. A continuación se muestran algunos ejemplos:
Ejemplo de nivel de clase:
[AutoValidateAntiforgeryToken]
public class HomeController : Controller
Ejemplo global:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
Invalidación de atributos de antifalsificación globales o de controlador
El filtro IgnoreAntiforgeryToken se usa para evitar tener que usar un token de antifalsificación para una acción determinada (o controlador). Cuando se aplica, este filtro invalida los filtros ValidateAntiForgeryToken y AutoValidateAntiforgeryToken especificados en un nivel superior (global o en un controlador).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Actualización de tokens después de la autenticación
Los tokens se deben actualizar después de que el usuario se autentique al redirigir al usuario a una vista o página de Razor Pages.
JavaScript, AJAX y SPA
En las aplicaciones tradicionales basadas en HTML, los tokens de antifalsificación se pasan al servidor mediante campos de formulario ocultos. En las aplicaciones y SPA modernas basadas en JavaScript, muchas solicitudes se realizan mediante programación. Estas solicitudes de AJAX pueden usar otras técnicas, como encabezados de solicitud o cookies, para enviar el token.
Si se usan cookies para almacenar tokens de autenticación y para autenticar solicitudes de API en el servidor, la CSRF es un posible problema. Si el almacenamiento local se usa para almacenar el token, se podría mitigar la vulnerabilidad de CSRF porque los valores del almacenamiento local no se envían automáticamente al servidor con cada solicitud. El uso del almacenamiento local para almacenar el token de antifalsificación en el cliente y enviar el token como encabezado de solicitud es un enfoque recomendado.
Blazor
Para obtener más información, consulte AutenticaciónBlazor y autorización de ASP.NET Core.
JavaScript
Al usar JavaScript con vistas, el token se puede crear mediante un servicio desde dentro de la vista. Inserte el servicio IAntiforgery en la vista y luego llame a 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>
}
En el ejemplo anterior se usa JavaScript para leer el valor de campo oculto del encabezado POST de AJAX.
Este enfoque evita tener que tratar directamente con la configuración de cookies del servidor o leerlas del cliente. Sin embargo, si no es posible insertar el servicio IAntiforgery, usa JavaScript para acceder a tokens en cookies:
- Acceda a tokens en una solicitud adicional al servidor, normalmente
same-origin. - Use el contenido de la cookie para crear un encabezado con el valor del token.
Suponiendo que el script envía el token en un encabezado de solicitud denominado X-XSRF-TOKEN, configure el servicio de antifalsificación para buscar el encabezado X-XSRF-TOKEN:
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
En el ejemplo siguiente se agrega un punto de conexión protegido que escribe el token de solicitud en una cookie legible en 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();
En el ejemplo siguiente se usa JavaScript para realizar una solicitud de AJAX para obtener el token y realizar otra solicitud con el encabezado adecuado:
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}`
}
Nota:
Cuando el token antifalsificación se proporciona tanto en la cabecera de la solicitud como en la carga útil del formulario, sólo se valida el token de la cabecera.
Antifalsificación con API mínimas
Llame a AddAntiforgery y UseAntiforgery(IApplicationBuilder) para registrar servicios de antifalsificación en la inserción de dependencias. Los tokens de antifalsificación se usan para mitigar losataques de falsificación de solicitud entre sitios.
var builder = WebApplication.CreateBuilder();
builder.Services.AddAntiforgery();
var app = builder.Build();
app.UseAntiforgery();
app.MapGet("/", () => "Hello World!");
app.Run();
Middleware de antifalsificación:
- No cortocircuita la ejecución del resto de la canalización de solicitudes.
- Establece el IAntiforgeryValidationFeature en el HttpContext.Features de la petición actual.
El token de antifalsificación solo se valida si:
- El punto de conexión contiene metadatos que implementan IAntiforgeryMetadata donde
RequiresValidation=true. - El método HTTP asociado al punto de conexión es un método HTTP relevante de tipo POST, PUT o PATCH.
- La solicitud está asociada a un punto de conexión válido.
El middleware contra falsificación no interrumpe la canalización de solicitudes. El código de punto de conexión siempre se ejecuta, incluso si se produce un error en la validación de tokens. Para observar el resultado de la validación del token, resuelva el IAntiforgeryValidationFeature desde HttpContext.Features e inspeccione su propiedad IsValid o la propiedad Error para obtener detalles de la falla. Este enfoque es útil cuando los puntos de conexión requieren un manejo personalizado para la validación antifalsificación fallida.
Nota: cuando se habilita manualmente, el middleware de antifalsificación debe ejecutarse después del middleware de autenticación y autorización para evitar la lectura de datos del formulario cuando el usuario no está autenticado.
De forma predeterminada, las API mínimas que aceptan datos de formulario requieren validación de tokens antiforgería y producen un error antes de ejecutar código de aplicación si la validación antiforgería no se realiza correctamente.
Observe el método GenerateForm siguiente:
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>
";
}
El código anterior tiene tres argumentos, la acción, el token antifalsificación y un elemento bool que indica si se debe usar el token.
Observe el ejemplo siguiente:
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>
";
}
}
En el código anterior se envía a:
-
/todorequerir un token de antifalsificación válido. -
/todo2no requieren un token de antifalsificación válido porque se llama a DisableAntiforgery.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));
app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
.DisableAntiforgery();
Advertencia
La llamada .DisableAntiforgery() deshabilita la protección contra la falsificación de solicitud entre sitios (CSRF) para el endpoint. Esto solo se debe usar cuando un punto de conexión no es vulnerable a ataques CSRF, como:
- Puntos de conexión que no se pueden llamar desde un explorador (por ejemplo, API internas)
- Puntos de conexión protegidos con autenticación no basada en cookie (por ejemplo, tokens de portadora o claves API)
- Puntos de conexión internos o de infraestructura que no dependen de cookies de usuario
No deshabilite la validación antiforgería para los puntos de conexión accesibles para exploradores que dependen de cookies para la autenticación o que procesan los datos de formulario enviados por el usuario, ya que esto expone la aplicación a ataques CSRF.
Una MENSAJE para:
-
/tododel formulario generado por el punto de conexión/se realiza correctamente porque el token de antifalsificación es válido. -
/tododel formulario generado por el error/SkipTokenporque no se incluye la antifalsificación. -
/todo2del formulario generado por el punto de conexión/DisableAntiforgeryse realiza correctamente porque no se requiere la antifalsificación.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));
app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
.DisableAntiforgery();
Cuando se envía un formulario sin un token de antifalsificación válido:
- En el
Developmententorno, se produce una excepción. - En el
Productionentorno, se registra un mensaje.
Limitaciones del método HTTP e HttpMethodOverrideMiddleware interacción
Para el método antifalsificación basado en middleware, AntiforgeryMiddleware y UseAntiforgery() validan los tokens de antifalsificación solo para las solicitudes HTTP POST, PUT y PATCH. Otros métodos HTTP, como DELETE, no se validan automáticamente.
Para validar tokens antifalsificación para otros métodos HTTP, resuelva IAntiforgery desde DI y llame a ValidateRequestAsync o IsRequestValidAsync explícitamente:
app.MapDelete("/item/{id}", async (int id, IAntiforgery antiforgery, HttpContext context) =>
{
await antiforgery.ValidateRequestAsync(context);
// Process the DELETE request
});
Advertencia
Cuando HttpMethodOverrideMiddleware se configura con FormFieldName (modo de campo de formulario) y se coloca antes de AntiforgeryMiddleware, una solicitud POST puede sustituirse por DELETE (u otro método no validado). Dado que AntiforgeryMiddleware valida solo POST, PUT y PATCH, la solicitud invalidada omite la validación antiforgería.
Para proteger estos puntos de conexión:
- Es preferible colocar
HttpMethodOverrideMiddlewaredespués de la validación antifalsificación si tu flujo de procesamiento lo permite. - Evite sobrescribir campos de formulario en los endpoints que dependen de la validación antifalsificación.
- Si la anulación del campo de formulario debe ejecutarse primero, valide explícitamente el token contra falsificación mediante
IAntiforgery.ValidateRequestAsync.
Para obtener más información sobre la configuración, consulte ASP.NET Core middleware.
Autenticación de Windows y cookies antifalsificación
Al usar la autenticación de Windows, los puntos de conexión de la aplicación deben protegerse frente a ataques de CSRF de la misma manera que se hace para las cookies. El explorador envía implícitamente el contexto de autenticación al servidor y los puntos de conexión deben protegerse frente a ataques de CSRF.
Extensión de la antifalsificación
El tipo IAntiforgeryAdditionalDataProvider permite a los desarrolladores ampliar el comportamiento del sistema anti-CSRF mediante el recorrido de ida y vuelta de datos adicionales en cada token. Se llama al método GetAdditionalData cada vez que se genera un token de campo; el valor devuelto se inserta dentro del token generado. Un implementador podría devolver una marca de tiempo, un valor nonce o cualquier otro valor y, a continuación, llamar a ValidateAdditionalData para validar estos datos cuando se valida el token. El nombre de usuario del cliente ya está insertado en los tokens generados, por lo que no es necesario incluir esta información. Si un token incluye datos complementarios pero no se configura un IAntiForgeryAdditionalDataProvider, los datos complementarios no se validan.
Recursos adicionales
La falsificación de solicitud entre sitios (también conocida como XSRF o CSRF) es un ataque contra aplicaciones hospedadas en web, en el que una aplicación web malintencionada puede influir en la interacción entre un explorador cliente y una aplicación web que confía en ese explorador. Estos ataques son posibles porque los exploradores web envían automáticamente algunos tipos de token de autenticación con cada solicitud en un sitio web. Esta forma de exploit también se conoce como ataque con un clic o secuestro de sesión porque el ataque aprovecha la sesión autenticada previamente del usuario.
Ejemplo de un ataque de CSRF:
Un usuario inicia sesión en
www.good-banking-site.example.comcon la autenticación de formularios. El servidor autentica al usuario y emite una respuesta que incluye una autenticación cookie. El sitio es vulnerable a ataques porque confía en cualquier solicitud que reciba con una cookie de autenticación válida.El usuario visita un sitio malintencionado,
www.bad-crook-site.example.com.El sitio malintencionado,
www.bad-crook-site.example.com, contiene un formulario HTML similar al ejemplo siguiente:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.example.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 el
actiondel formulario publica en el sitio vulnerable, no en el sitio malintencionado. Esta es la parte "entre sitios" de CSRF.El usuario selecciona el botón Enviar. El explorador realiza la solicitud e incluye automáticamente la cookie de autenticación para el dominio solicitado,
www.good-banking-site.example.com.La solicitud se ejecuta en el servidor de
www.good-banking-site.example.comcon el contexto de autenticación del usuario y puede realizar cualquier acción que un usuario autenticado pueda realizar.
Además del escenario en el que el usuario selecciona el botón para enviar el formulario, el sitio malintencionado podría:
- Ejecutar un script que envíe automáticamente el formulario.
- Enviar el envío del formulario como una solicitud AJAX.
- Ocultar el formulario mediante CSS.
Estos escenarios alternativos no requieren ninguna acción ni entrada por parte del usuario aparte de visitar inicialmente el sitio malintencionado.
El uso de HTTPS no impide un ataque de CSRF. El sitio malintencionado puede enviar https://www.good-banking-site.example.com/ una solicitud tan fácilmente como puede enviar una solicitud no segura.
Algunos ataques se dirigen a puntos de conexión que responden a solicitudes GET, en cuyo caso se puede usar una etiqueta de imagen para realizar la acción. Esta forma de ataque es común en sitios de foros que permiten imágenes pero bloquean JavaScript. Las aplicaciones que cambian el estado de las solicitudes GET, en las que se modifican variables o recursos, son vulnerables a ataques malintencionados. Las solicitudes GET que cambian de estado no son seguras. Un procedimiento recomendado es no cambiar nunca el estado en una solicitud GET.
Los ataques de CSRF se pueden producir en las aplicaciones web que usan cookies para la autenticación porque:
- Los exploradores almacenan cookies emitidas por una aplicación web.
- Las cookies almacenadas incluyen cookies de sesión para los usuarios autenticados.
- Los exploradores envían todas las cookies asociadas con un dominio a la aplicación web en cada solicitud independientemente de cómo se generó la solicitud a la aplicación en el explorador.
Sin embargo, los ataques CSRF no se limitan a aprovechar las vulnerabilidades de las cookies. Por ejemplo, la autenticación básica y Digest también son vulnerables. Una vez que un usuario inicia sesión con la autenticación básica o implícita, el explorador envía automáticamente las credenciales hasta que finaliza la sesión.
En este contexto, la sesión hace referencia a la sesión del lado cliente durante la cual se autentica el usuario. No está relacionado con las sesiones del servidor ni con el middleware de sesión de ASP.NET Core.
Para protegerse contra las vulnerabilidades de CSRF, los usuarios pueden tomar precauciones:
- Cierre la sesión de las aplicaciones web cuando termine de usarlas.
- Borra periódicamente las cookies del explorador.
Sin embargo, las vulnerabilidades de CSRF son fundamentalmente un problema con la aplicación web, no con el usuario final.
Aspectos básicos de la autenticación
La autenticación basada en Cookie es una forma popular de autenticación. Los sistemas de autenticación basados en tokens están creciendo en popularidad, especialmente para aplicaciones de página única (SPA).
Autenticación basada en Cookie
Cuando un usuario se autentica con su nombre de usuario y contraseña, se emite un token que contiene un vale de autenticación que se puede usar para la autenticación y la autorización. El token se almacena como una cookie que se envía con cada solicitud que realiza el cliente. La generación y validación de este cookie las realiza el middleware de autenticación cookie. El middleware serializa una entidad de seguridad de usuario en una cookie cifrada. En las solicitudes posteriores, el middleware valida la cookie, vuelve a crear la entidad de seguridad y asigna la entidad de seguridad a la propiedad HttpContext.User.
Autenticación basada en tokens
Cuando se autentica un usuario, se emite un token (no un token de antifalsificación). El token contiene información de usuario en forma de notificaciones o un token de referencia que apunta la aplicación al estado de usuario mantenido en la aplicación. Cuando un usuario intenta acceder a un recurso que requiere autenticación, el token se envía a la aplicación con un encabezado de autorización adicional en forma de token de portador. Este enfoque hace que la aplicación no tenga estado. En cada solicitud posterior, el token se pasa en la solicitud de validación del lado servidor. Este token no está cifrado; está codificado. En el servidor, el token se descodifica para acceder a su información. Para enviar el token en solicitudes posteriores, almacene el token en el almacenamiento local del explorador. Colocar un token en el almacenamiento local del explorador, recuperarlo y usarlo como token de portador proporciona protección contra ataques de CSRF. Sin embargo, si la aplicación es vulnerable a la inserción de scripts a través de XSS o un archivo JavaScript externo en peligro, un ciberdelincuente podría recuperar cualquier valor del almacenamiento local y enviárselo a sí mismo. ASP.NET Core codifica todas las salidas del lado servidor de las variables de forma predeterminada, lo que reduce el riesgo de XSS. Si invalida este comportamiento mediante Html.Raw o código personalizado con entradas que no son de confianza, puede aumentar el riesgo de XSS.
No se preocupe por la vulnerabilidad de CSRF si el token se almacena en el almacenamiento local del explorador. La CSRF es un problema cuando el token se almacena en una cookie. Para obtener más información, consulta el problema de GitHub El ejemplo de código SPA agrega dos cookies.
Varias aplicaciones hospedadas en un dominio
Los entornos de hospedaje compartidos son vulnerables al secuestro de sesión, a la CSRF de inicio de sesión y a otros ataques.
Aunque example1.contoso.net y example2.contoso.net son hosts diferentes, hay una relación de confianza implícita entre los hosts bajo el dominio *.contoso.net. Esta relación de confianza implícita permite que hosts que podrían no ser de confianza afecten a las cookies de otros hosts (las directivas de mismo origen que rigen las solicitudes AJAX no se aplican necesariamente a las cookies HTTP).
Los ataques que aprovechan las cookies de confianza entre aplicaciones hospedadas en el mismo dominio pueden evitarse si no se comparten dominios. Cuando cada aplicación se hospeda en su propio dominio, no hay ninguna relación de confianza implícita que se pueda aprovechar.
Antifalsificación en ASP.NET Core
Advertencia
ASP.NET Core implementa la antifalsificación mediante la Protección de datos de ASP.NET Core. La pila de protección de datos debe configurarse para que funcione en una granja de servidores. Para obtener más información, consulte Configuración de la protección de datos.
El middleware de antifalsificación se agrega al contenedor de inserción de dependencias cuando se llama a una de las siguientes API en Program.cs:
El elemento FormTagHelper inserta tokens antifalsificación en los elementos de formulario HTML. El siguiente marcado en un archivo de Razor genera automáticamente tokens de antifalsificación:
<form method="post">
<!-- ... -->
</form>
De forma similar, IHtmlHelper.BeginForm genera tokens antifalsificación de forma predeterminada si el método del formulario no es GET.
La generación automática de tokens de antifalsificación para elementos de formulario HTML se produce cuando la etiqueta <form> contiene el atributo method="post" y se cumple alguna de las siguientes condiciones:
- El atributo action está vacío (
action=""). - El atributo action no se proporciona (
<form method="post">).
La generación automática de tokens de antifalsificación para elementos de formulario HTML se puede deshabilitar:
Deshabilite explícitamente los tokens de antifalsificación con el atributo
asp-antiforgery.<form method="post" asp-antiforgery="false"> <!-- ... --> </form>El elemento de formulario se ha excluido de los asistentes de etiquetas mediante el símbolo de rechazo ! del asistente de etiquetas:
<!form method="post"> <!-- ... --> </!form>Quite
FormTagHelperde la vista.FormTagHelperpuede eliminarse de una vista mediante la adición de la siguiente directiva a la vista Razor.@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Nota:
Las Razor páginas están protegidas automáticamente contra XSRF/CSRF. Para obtener más información, vea XSRF/CSRF y Razor Pages.
El enfoque más común para defenderse contra ataques de CSRF es usar el patrón de token del sincronizador (STP). El STP se usa cuando el usuario solicita una página con datos de formulario:
- El servidor envía un token asociado a la identidad del usuario actual al cliente.
- El cliente devuelve el token al servidor para su comprobación.
- Si el servidor recibe un token que no coincide con la identidad del usuario autenticado, se rechaza la solicitud.
El token es único e imprevisible. El token también se puede usar para garantizar la secuenciación correcta de una serie de solicitudes (por ejemplo, garantizar la secuencia de solicitudes de: página 1 > página 2 > página 3). Todos los formularios de las plantillas de Razor Pages y de ASP.NET Core MVC generan tokens de antifalsificación. El siguiente par de ejemplos de vista genera tokens de antifalsificación:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Agregue explícitamente un token de antifalsificación a un elemento <form> sin usar asistentes de etiquetas con el asistente de HTML @Html.AntiForgeryToken:
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
En cada uno de los casos anteriores, ASP.NET Core agrega un campo de formulario oculto similar al ejemplo siguiente:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core incluye tres filtros para trabajar con tokens de antifalsificación:
Antifraude con AddControllers
La llamada a AddControllersno habilita tokens de antifalsificación. Se debe llamar a AddControllersWithViews para tener compatibilidad integrada con tokens de antifalsificación.
Varias pestañas del explorador y el patrón de token del sincronizador
Con el patrón de token del sincronizador, solo la página cargada más recientemente contiene un token de antifalsificación válido. El uso de varias pestañas puede ser problemático. Por ejemplo, si un usuario abre varias pestañas:
- Solo la pestaña cargada más recientemente contiene un token de antifalsificación válido.
- Las solicitudes realizadas desde pestañas cargadas anteriormente producen un error:
Antiforgery token validation failed. The antiforgery cookie token and request token do not match
Considere la posibilidad de usar patrones alternativos de protección contra CSRF si esto plantea un problema.
Configurar el sistema antifalsificación con AntiforgeryOptions
Personalice AntiforgeryOptions en el archivo Program de la aplicación.
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties†.
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Establezca las propiedades de la cookie de antifalsificación mediante las propiedades de la clase CookieBuilder, como se muestra en la tabla siguiente.
| Opción | Descripción |
|---|---|
| Cookie | Determina la configuración usada para crear las cookies de antifalsificación. |
| FormFieldName | Nombre del campo de formulario oculto utilizado por el sistema de antifalsificación para representar tokens de antifalsificación en vistas. |
| HeaderName | Nombre del encabezado utilizado por el sistema de antifalsificación. Si es null, el sistema solo tiene en cuenta los datos del formulario. |
| SuppressXFrameOptionsHeader | Especifica si se va a suprimir la generación del encabezado X-Frame-Options. De forma predeterminada, el encabezado se genera con un valor de "SAMEORIGIN". Tiene como valor predeterminado false. |
Algunos exploradores no permiten que los puntos de conexión inseguros establezcan cookies con una marca "segura" o sobrescribir cookies cuya marca "segura" está establecida (para obtener más información, consulte Desuso de la modificación de cookies "seguras" de orígenes no seguros). Dado que la combinación de puntos de conexión seguros e inseguros es un escenario común en las aplicaciones, ASP.NET Core relaja la restricción de la directiva segura en algunas cookies, como la antifalsificación cookie, estableciendo el cookie de SecurePolicy en CookieSecurePolicy.None. Incluso si un usuario malintencionado roba un elemento de antifalsificación cookie, también debe robar el token de antifalsificación que normalmente se envía a través de un campo de formulario (más común) o de un encabezado de solicitud independiente (menos común), además de la autenticación cookie. Las cookies relacionadas con la autenticación o autorización usan una directiva más fuerte que CookieSecurePolicy.None.
Opcionalmente, puede proteger la protección contra falsificación cookie en entornos que no sean Development utilizando Capa de Conexión Segura (SSL), a través solo de HTTPS, estableciendo la siguiente propiedad AntiforgeryOptions.Cookie en el archivo de la aplicación Program.
if (!builder.Environment.IsDevelopment())
{
builder.Services.AddAntiforgery(o =>
{
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
}
Para obtener más información, vea CookieAuthenticationOptions.
Generación de tokens de antifalsificación con IAntiforgery
IAntiforgeryproporciona la API para configurar características de antifalsificación.
IAntiforgery se puede solicitar en Program.cs mediante WebApplication.Services. En el ejemplo siguiente se usa middleware desde la página principal de la aplicación para generar un token de antiforgería y enviarlo en la respuesta como un 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);
});
En el ejemplo anterior se establece una cookie denominada XSRF-TOKEN. El cliente puede leer esta cookie y proporcionar su valor como un encabezado adjunto a las solicitudes de AJAX. Por ejemplo, Angular incluye protección integrada contra XSRF que lee una cookie denominada XSRF-TOKEN de forma predeterminada.
Requerir validación de antifalsificación
El filtro de acción ValidateAntiForgeryToken se puede aplicar a una acción individual, un controlador o globalmente. Las solicitudes realizadas a las acciones que tienen aplicado este filtro se bloquean a menos que la solicitud incluya un token de antifalsificación válido:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
El atributo ValidateAntiForgeryToken requiere un token para las solicitudes a los métodos de acción que marca, incluidas las solicitudes HTTP GET. Si el atributo ValidateAntiForgeryToken se aplica en los controladores de la aplicación, se puede invalidar con el atributo IgnoreAntiforgeryToken.
Validar automáticamente tokens de antifalsificación solo para métodos HTTP no seguros
En lugar de aplicar ampliamente el atributo ValidateAntiForgeryToken y, a continuación, reemplazarlo con atributos IgnoreAntiforgeryToken, se puede usar el atributo AutoValidateAntiforgeryToken. Este atributo funciona de forma idéntica al atributo ValidateAntiForgeryToken, salvo que no requiere tokens para las solicitudes realizadas mediante los siguientes métodos HTTP:
- GET
- HEAD
- Opciones
- TRACE
Se recomienda usar ampliamente AutoValidateAntiforgeryToken para escenarios que no son de API. Este atributo garantiza que las acciones POST estén protegidas de forma predeterminada. La alternativa es omitir los tokens de antifalsificación de forma predeterminada, a menos que ValidateAntiForgeryToken se aplique a métodos de acción individuales. Es más probable que en este escenario un método de acción POST se deje desprotegido por error, lo que hace que la aplicación sea vulnerable a los ataques de CSRF. Todos los POST deben enviar el token de antifalsificación.
Las API no tienen un mecanismo automático para enviar la parte del token que no es una cookie. La implementación probablemente depende de la implementación del código de cliente. A continuación se muestran algunos ejemplos:
Ejemplo de nivel de clase:
[AutoValidateAntiforgeryToken]
public class HomeController : Controller
Ejemplo global:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
Invalidación de atributos de antifalsificación globales o de controlador
El filtro IgnoreAntiforgeryToken se usa para evitar tener que usar un token de antifalsificación para una acción determinada (o controlador). Cuando se aplica, este filtro invalida los filtros ValidateAntiForgeryToken y AutoValidateAntiforgeryToken especificados en un nivel superior (global o en un controlador).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Actualización de tokens después de la autenticación
Los tokens se deben actualizar después de que el usuario se autentique al redirigir al usuario a una vista o página de Razor Pages.
JavaScript, AJAX y SPA
En las aplicaciones tradicionales basadas en HTML, los tokens de antifalsificación se pasan al servidor mediante campos de formulario ocultos. En las aplicaciones y SPA modernas basadas en JavaScript, muchas solicitudes se realizan mediante programación. Estas solicitudes de AJAX pueden usar otras técnicas (como encabezados de solicitud o cookies) para enviar el token.
Si se usan cookies para almacenar tokens de autenticación y para autenticar solicitudes de API en el servidor, la CSRF es un posible problema. Si el almacenamiento local se usa para almacenar el token, se podría mitigar la vulnerabilidad de CSRF porque los valores del almacenamiento local no se envían automáticamente al servidor con cada solicitud. El uso del almacenamiento local para almacenar el token de antifalsificación en el cliente y enviar el token como encabezado de solicitud es un enfoque recomendado.
JavaScript
Al usar JavaScript con vistas, el token se puede crear mediante un servicio desde dentro de la vista. Inserte el servicio IAntiforgery en la vista y luego llame a 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>
}
En el ejemplo anterior se usa JavaScript para leer el valor de campo oculto del encabezado POST de AJAX.
Este enfoque evita tener que tratar directamente con la configuración de cookies del servidor o leerlas del cliente. Sin embargo, si no es posible insertar el servicio IAntiforgery, usa JavaScript para acceder a tokens en cookies:
- Acceda a tokens en una solicitud adicional al servidor, normalmente
same-origin. - Use el contenido de la cookie para crear un encabezado con el valor del token.
Suponiendo que el script envía el token en un encabezado de solicitud denominado X-XSRF-TOKEN, configure el servicio de antifalsificación para buscar el encabezado X-XSRF-TOKEN:
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
En el ejemplo siguiente se agrega un punto de conexión protegido que escribe el token de solicitud en una cookie legible en 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();
En el ejemplo siguiente se usa JavaScript para realizar una solicitud de AJAX para obtener el token y realizar otra solicitud con el encabezado adecuado:
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}`
}
Nota:
Cuando el token antifalsificación se proporciona tanto en la cabecera de la solicitud como en la carga útil del formulario, sólo se valida el token de la cabecera.
Antifalsificación con API mínimas
Las Minimal APIs no admiten el uso de los filtros incluidos (ValidateAntiForgeryToken, AutoValidateAntiforgeryToken, IgnoreAntiforgeryToken); sin embargo, IAntiforgery proporciona las API necesarias para validar una solicitud.
En el ejemplo siguiente se crea un filtro que valida el token de antifalsificación:
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);
});
}
}
A continuación, el filtro puede aplicarse a un extremo.
app.MapPost("api/upload", (IFormFile name) => Results.Accepted())
.RequireAuthorization()
.ValidateAntiforgery();
Autenticación de Windows y cookies antifalsificación
Al usar la autenticación de Windows, los puntos de conexión de la aplicación deben protegerse frente a ataques de CSRF de la misma manera que se hace para las cookies. El explorador envía implícitamente el contexto de autenticación al servidor y los puntos de conexión deben protegerse frente a ataques de CSRF.
Extensión de la antifalsificación
El tipo IAntiforgeryAdditionalDataProvider permite a los desarrolladores ampliar el comportamiento del sistema anti-CSRF mediante el recorrido de ida y vuelta de datos adicionales en cada token. Se llama al método GetAdditionalData cada vez que se genera un token de campo; el valor devuelto se inserta dentro del token generado. Un implementador podría devolver una marca de tiempo, un valor nonce o cualquier otro valor y, a continuación, llamar a ValidateAdditionalData para validar estos datos cuando se valida el token. El nombre de usuario del cliente ya está insertado en los tokens generados, por lo que no es necesario incluir esta información. Si un token incluye datos complementarios pero no se configura un IAntiForgeryAdditionalDataProvider, los datos complementarios no se validan.
Recursos adicionales
La falsificación de solicitud entre sitios (también conocida como XSRF o CSRF) es un ataque contra aplicaciones hospedadas en web, en el que una aplicación web malintencionada puede influir en la interacción entre un explorador cliente y una aplicación web que confía en ese explorador. Estos ataques son posibles porque los exploradores web envían automáticamente algunos tipos de token de autenticación con cada solicitud en un sitio web. Esta forma de exploit también se conoce como ataque con un clic o secuestro de sesión porque el ataque aprovecha la sesión autenticada previamente del usuario.
Ejemplo de un ataque de CSRF:
Un usuario inicia sesión en
www.good-banking-site.example.comcon la autenticación de formularios. El servidor autentica al usuario y emite una respuesta que incluye una autenticación cookie. El sitio es vulnerable a ataques porque confía en cualquier solicitud que reciba con una cookie de autenticación válida.El usuario visita un sitio malintencionado,
www.bad-crook-site.example.com.El sitio malintencionado,
www.bad-crook-site.example.com, contiene un formulario HTML similar al ejemplo siguiente:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.example.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 el
actiondel formulario publica en el sitio vulnerable, no en el sitio malintencionado. Esta es la parte "entre sitios" de CSRF.El usuario selecciona el botón Enviar. El explorador realiza la solicitud e incluye automáticamente la cookie de autenticación para el dominio solicitado,
www.good-banking-site.example.com.La solicitud se ejecuta en el servidor de
www.good-banking-site.example.comcon el contexto de autenticación del usuario y puede realizar cualquier acción que un usuario autenticado pueda realizar.
Además del escenario en el que el usuario selecciona el botón para enviar el formulario, el sitio malintencionado podría:
- Ejecutar un script que envíe automáticamente el formulario.
- Enviar el envío del formulario como una solicitud AJAX.
- Ocultar el formulario mediante CSS.
Estos escenarios alternativos no requieren ninguna acción ni entrada por parte del usuario aparte de visitar inicialmente el sitio malintencionado.
El uso de HTTPS no impide un ataque de CSRF. El sitio malintencionado puede enviar https://www.good-banking-site.example.com/ una solicitud tan fácilmente como puede enviar una solicitud no segura.
Algunos ataques se dirigen a puntos de conexión que responden a solicitudes GET, en cuyo caso se puede usar una etiqueta de imagen para realizar la acción. Esta forma de ataque es común en sitios de foros que permiten imágenes pero bloquean JavaScript. Las aplicaciones que cambian el estado de las solicitudes GET, en las que se modifican variables o recursos, son vulnerables a ataques malintencionados. Las solicitudes GET que cambian de estado no son seguras. Un procedimiento recomendado es no cambiar nunca el estado en una solicitud GET.
Los ataques de CSRF se pueden producir en las aplicaciones web que usan cookies para la autenticación porque:
- Los exploradores almacenan cookies emitidas por una aplicación web.
- Las cookies almacenadas incluyen cookies de sesión para los usuarios autenticados.
- Los exploradores envían todas las cookies asociadas con un dominio a la aplicación web en cada solicitud independientemente de cómo se generó la solicitud a la aplicación en el explorador.
Sin embargo, los ataques CSRF no se limitan a aprovechar las vulnerabilidades de las cookies. Por ejemplo, la autenticación básica y Digest también son vulnerables. Una vez que un usuario inicia sesión con la autenticación básica o implícita, el explorador envía automáticamente las credenciales hasta que finaliza la sesión.
En este contexto, la sesión hace referencia a la sesión del lado cliente durante la cual se autentica el usuario. No está relacionado con las sesiones del servidor ni con el middleware de sesión de ASP.NET Core.
Para protegerse contra las vulnerabilidades de CSRF, los usuarios pueden tomar precauciones:
- Cierre la sesión de las aplicaciones web cuando termine de usarlas.
- Borra periódicamente las cookies del explorador.
Sin embargo, las vulnerabilidades de CSRF son fundamentalmente un problema con la aplicación web, no con el usuario final.
Aspectos básicos de la autenticación
La autenticación basada en Cookie es una forma popular de autenticación. Los sistemas de autenticación basados en tokens están creciendo en popularidad, especialmente para aplicaciones de página única (SPA).
Autenticación basada en Cookie
Cuando un usuario se autentica con su nombre de usuario y contraseña, se emite un token que contiene un vale de autenticación que se puede usar para la autenticación y la autorización. El token se almacena como una cookie que se envía con cada solicitud que realiza el cliente. La generación y validación de este cookie las realiza el middleware de autenticación cookie. El middleware serializa una entidad de seguridad de usuario en una cookie cifrada. En las solicitudes posteriores, el middleware valida la cookie, vuelve a crear la entidad de seguridad y asigna la entidad de seguridad a la propiedad HttpContext.User.
Autenticación basada en tokens
Cuando se autentica un usuario, se emite un token (no un token de antifalsificación). El token contiene información de usuario en forma de notificaciones o un token de referencia que apunta la aplicación al estado de usuario mantenido en la aplicación. Cuando un usuario intenta acceder a un recurso que requiere autenticación, el token se envía a la aplicación con un encabezado de autorización adicional en forma de token de portador. Este enfoque hace que la aplicación no tenga estado. En cada solicitud posterior, el token se pasa en la solicitud de validación del lado servidor. Este token no está cifrado; está codificado. En el servidor, el token se descodifica para acceder a su información. Para enviar el token en solicitudes posteriores, almacene el token en el almacenamiento local del explorador. No se preocupe por la vulnerabilidad de CSRF si el token se almacena en el almacenamiento local del explorador. La CSRF es un problema cuando el token se almacena en una cookie. Para obtener más información, consulta el problema de GitHub El ejemplo de código SPA agrega dos cookies.
Varias aplicaciones hospedadas en un dominio
Los entornos de hospedaje compartidos son vulnerables al secuestro de sesión, a la CSRF de inicio de sesión y a otros ataques.
Aunque example1.contoso.net y example2.contoso.net son hosts diferentes, hay una relación de confianza implícita entre los hosts bajo el dominio *.contoso.net. Esta relación de confianza implícita permite que hosts que podrían no ser de confianza afecten a las cookies de otros hosts (las directivas de mismo origen que rigen las solicitudes AJAX no se aplican necesariamente a las cookies HTTP).
Los ataques que aprovechan las cookies de confianza entre aplicaciones hospedadas en el mismo dominio pueden evitarse si no se comparten dominios. Cuando cada aplicación se hospeda en su propio dominio, no hay ninguna relación de confianza implícita que se pueda aprovechar.
Antifalsificación en ASP.NET Core
Advertencia
ASP.NET Core implementa la antifalsificación mediante la Protección de datos de ASP.NET Core. La pila de protección de datos debe configurarse para que funcione en una granja de servidores. Para obtener más información, consulte Configuración de la protección de datos.
El middleware de antifalsificación se agrega al contenedor de inserción de dependencias cuando se llama a una de las siguientes API en Program.cs:
El elemento FormTagHelper inserta tokens antifalsificación en los elementos de formulario HTML. El siguiente marcado en un archivo de Razor genera automáticamente tokens de antifalsificación:
<form method="post">
<!-- ... -->
</form>
De forma similar, IHtmlHelper.BeginForm genera tokens antifalsificación de forma predeterminada si el método del formulario no es GET.
La generación automática de tokens de antifalsificación para elementos de formulario HTML se produce cuando la etiqueta <form> contiene el atributo method="post" y se cumple alguna de las siguientes condiciones:
- El atributo action está vacío (
action=""). - El atributo action no se proporciona (
<form method="post">).
La generación automática de tokens de antifalsificación para elementos de formulario HTML se puede deshabilitar:
Deshabilite explícitamente los tokens de antifalsificación con el atributo
asp-antiforgery.<form method="post" asp-antiforgery="false"> <!-- ... --> </form>El elemento de formulario se ha excluido de los asistentes de etiquetas mediante el símbolo de rechazo ! del asistente de etiquetas:
<!form method="post"> <!-- ... --> </!form>Quite
FormTagHelperde la vista.FormTagHelperpuede eliminarse de una vista mediante la adición de la siguiente directiva a la vista Razor.@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Nota:
Las Razor páginas están protegidas automáticamente contra XSRF/CSRF. Para obtener más información, vea XSRF/CSRF y Razor Pages.
El enfoque más común para defenderse contra ataques de CSRF es usar el patrón de token del sincronizador (STP). El STP se usa cuando el usuario solicita una página con datos de formulario:
- El servidor envía un token asociado a la identidad del usuario actual al cliente.
- El cliente devuelve el token al servidor para su comprobación.
- Si el servidor recibe un token que no coincide con la identidad del usuario autenticado, se rechaza la solicitud.
El token es único e imprevisible. El token también se puede usar para garantizar la secuenciación correcta de una serie de solicitudes (por ejemplo, garantizar la secuencia de solicitudes de: página 1 > página 2 > página 3). Todos los formularios de las plantillas de Razor Pages y de ASP.NET Core MVC generan tokens de antifalsificación. El siguiente par de ejemplos de vista genera tokens de antifalsificación:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Agregue explícitamente un token de antifalsificación a un elemento <form> sin usar asistentes de etiquetas con el asistente de HTML @Html.AntiForgeryToken:
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
En cada uno de los casos anteriores, ASP.NET Core agrega un campo de formulario oculto similar al ejemplo siguiente:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core incluye tres filtros para trabajar con tokens de antifalsificación:
Antifraude con AddControllers
La llamada a AddControllersno habilita tokens de antifalsificación. Se debe llamar a AddControllersWithViews para tener compatibilidad integrada con tokens de antifalsificación.
Varias pestañas del explorador y el patrón de token del sincronizador
Con el patrón de token del sincronizador, solo la página cargada más recientemente contiene un token de antifalsificación válido. El uso de varias pestañas puede ser problemático. Por ejemplo, si un usuario abre varias pestañas:
- Solo la pestaña cargada más recientemente contiene un token de antifalsificación válido.
- Las solicitudes realizadas desde pestañas cargadas anteriormente producen un error:
Antiforgery token validation failed. The antiforgery cookie token and request token do not match
Considere la posibilidad de usar patrones alternativos de protección contra CSRF si esto plantea un problema.
Configurar el sistema antifalsificación con AntiforgeryOptions
Personalice AntiforgeryOptions en el archivo Program de la aplicación.
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties†.
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Establezca las propiedades de la cookie de antifalsificación mediante las propiedades de la clase CookieBuilder, como se muestra en la tabla siguiente.
| Opción | Descripción |
|---|---|
| Cookie | Determina la configuración usada para crear las cookies de antifalsificación. |
| FormFieldName | Nombre del campo de formulario oculto utilizado por el sistema de antifalsificación para representar tokens de antifalsificación en vistas. |
| HeaderName | Nombre del encabezado utilizado por el sistema de antifalsificación. Si es null, el sistema solo tiene en cuenta los datos del formulario. |
| SuppressXFrameOptionsHeader | Especifica si se va a suprimir la generación del encabezado X-Frame-Options. De forma predeterminada, el encabezado se genera con un valor de "SAMEORIGIN". Tiene como valor predeterminado false. |
Algunos exploradores no permiten que los puntos de conexión inseguros establezcan cookies con una marca "segura" o sobrescribir cookies cuya marca "segura" está establecida (para obtener más información, consulte Desuso de la modificación de cookies "seguras" de orígenes no seguros). Dado que la combinación de puntos de conexión seguros e inseguros es un escenario común en las aplicaciones, ASP.NET Core relaja la restricción de la directiva segura en algunas cookies, como la antifalsificación cookie, estableciendo el cookie de SecurePolicy en CookieSecurePolicy.None. Incluso si un usuario malintencionado roba un elemento de antifalsificación cookie, también debe robar el token de antifalsificación que normalmente se envía a través de un campo de formulario (más común) o de un encabezado de solicitud independiente (menos común), además de la autenticación cookie. Las cookies relacionadas con la autenticación o autorización usan una directiva más fuerte que CookieSecurePolicy.None.
Opcionalmente, puede proteger la protección contra falsificación cookie en entornos que no sean Development utilizando Capa de Conexión Segura (SSL), a través solo de HTTPS, estableciendo la siguiente propiedad AntiforgeryOptions.Cookie en el archivo de la aplicación Program.
if (!builder.Environment.IsDevelopment())
{
builder.Services.AddAntiforgery(o =>
{
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
}
Para obtener más información, vea CookieAuthenticationOptions.
Generación de tokens de antifalsificación con IAntiforgery
IAntiforgeryproporciona la API para configurar características de antifalsificación.
IAntiforgery se puede solicitar en Program.cs mediante WebApplication.Services. En el ejemplo siguiente se usa middleware desde la página principal de la aplicación para generar un token de antiforgería y enviarlo en la respuesta como un 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);
});
En el ejemplo anterior se establece una cookie denominada XSRF-TOKEN. El cliente puede leer esta cookie y proporcionar su valor como un encabezado adjunto a las solicitudes de AJAX. Por ejemplo, Angular incluye protección integrada contra XSRF que lee una cookie denominada XSRF-TOKEN de forma predeterminada.
Requerir validación de antifalsificación
El filtro de acción ValidateAntiForgeryToken se puede aplicar a una acción individual, un controlador o globalmente. Las solicitudes realizadas a las acciones que tienen aplicado este filtro se bloquean a menos que la solicitud incluya un token de antifalsificación válido:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
El atributo ValidateAntiForgeryToken requiere un token para las solicitudes a los métodos de acción que marca, incluidas las solicitudes HTTP GET. Si el atributo ValidateAntiForgeryToken se aplica en los controladores de la aplicación, se puede invalidar con el atributo IgnoreAntiforgeryToken.
Validar automáticamente tokens de antifalsificación solo para métodos HTTP no seguros
En lugar de aplicar ampliamente el atributo ValidateAntiForgeryToken y, a continuación, reemplazarlo con atributos IgnoreAntiforgeryToken, se puede usar el atributo AutoValidateAntiforgeryToken. Este atributo funciona de forma idéntica al atributo ValidateAntiForgeryToken, salvo que no requiere tokens para las solicitudes realizadas mediante los siguientes métodos HTTP:
- GET
- HEAD
- Opciones
- TRACE
Se recomienda usar ampliamente AutoValidateAntiforgeryToken para escenarios que no son de API. Este atributo garantiza que las acciones POST estén protegidas de forma predeterminada. La alternativa es omitir los tokens de antifalsificación de forma predeterminada, a menos que ValidateAntiForgeryToken se aplique a métodos de acción individuales. Es más probable que en este escenario un método de acción POST se deje desprotegido por error, lo que hace que la aplicación sea vulnerable a los ataques de CSRF. Todos los POST deben enviar el token de antifalsificación.
Las API no tienen un mecanismo automático para enviar la parte del token que no es una cookie. La implementación probablemente depende de la implementación del código de cliente. A continuación se muestran algunos ejemplos:
Ejemplo de nivel de clase:
[AutoValidateAntiforgeryToken]
public class HomeController : Controller
Ejemplo global:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
Invalidación de atributos de antifalsificación globales o de controlador
El filtro IgnoreAntiforgeryToken se usa para evitar tener que usar un token de antifalsificación para una acción determinada (o controlador). Cuando se aplica, este filtro invalida los filtros ValidateAntiForgeryToken y AutoValidateAntiforgeryToken especificados en un nivel superior (global o en un controlador).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Actualización de tokens después de la autenticación
Los tokens se deben actualizar después de que el usuario se autentique al redirigir al usuario a una vista o página de Razor Pages.
JavaScript, AJAX y SPA
En las aplicaciones tradicionales basadas en HTML, los tokens de antifalsificación se pasan al servidor mediante campos de formulario ocultos. En las aplicaciones y SPA modernas basadas en JavaScript, muchas solicitudes se realizan mediante programación. Estas solicitudes de AJAX pueden usar otras técnicas (como encabezados de solicitud o cookies) para enviar el token.
Si se usan cookies para almacenar tokens de autenticación y para autenticar solicitudes de API en el servidor, la CSRF es un posible problema. Si el almacenamiento local se usa para almacenar el token, se podría mitigar la vulnerabilidad de CSRF porque los valores del almacenamiento local no se envían automáticamente al servidor con cada solicitud. El uso del almacenamiento local para almacenar el token de antifalsificación en el cliente y enviar el token como encabezado de solicitud es un enfoque recomendado.
JavaScript
Al usar JavaScript con vistas, el token se puede crear mediante un servicio desde dentro de la vista. Inserte el servicio IAntiforgery en la vista y luego llame a 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>
}
En el ejemplo anterior se usa JavaScript para leer el valor de campo oculto del encabezado POST de AJAX.
Este enfoque evita tener que tratar directamente con la configuración de cookies del servidor o leerlas del cliente. Sin embargo, si no es posible insertar el servicio IAntiforgery, JavaScript también puede acceder al token en cookies, que se obtiene de una solicitud adicional al servidor (normalmente same-origin) y usar el contenido de la cookie para crear un encabezado con el valor del token.
Suponiendo que el script envía el token en un encabezado de solicitud denominado X-XSRF-TOKEN, configure el servicio de antifalsificación para buscar el encabezado X-XSRF-TOKEN:
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
En el ejemplo siguiente se agrega un punto de conexión protegido que escribirá el token de solicitud en una cookie legible en 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();
En el ejemplo siguiente se usa JavaScript para realizar una solicitud de AJAX para obtener el token y realizar otra solicitud con el encabezado adecuado:
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}`
}
Autenticación de Windows y cookies antifalsificación
Al usar la autenticación de Windows, los puntos de conexión de la aplicación deben protegerse frente a ataques de CSRF de la misma manera que se hace para las cookies. El explorador envía implícitamente el contexto de autenticación al servidor y, por tanto, los puntos de conexión deben protegerse frente a ataques de CSRF.
Extensión de la antifalsificación
El tipo IAntiforgeryAdditionalDataProvider permite a los desarrolladores ampliar el comportamiento del sistema anti-CSRF mediante el recorrido de ida y vuelta de datos adicionales en cada token. Se llama al método GetAdditionalData cada vez que se genera un token de campo; el valor devuelto se inserta dentro del token generado. Un implementador podría devolver una marca de tiempo, un valor nonce o cualquier otro valor y, a continuación, llamar a ValidateAdditionalData para validar estos datos cuando se valida el token. El nombre de usuario del cliente ya está insertado en los tokens generados, por lo que no es necesario incluir esta información. Si un token incluye datos complementarios pero no se configura un IAntiForgeryAdditionalDataProvider, los datos complementarios no se validan.
Recursos adicionales
La falsificación de solicitud entre sitios (también conocida como XSRF o CSRF) es un ataque contra aplicaciones hospedadas en web, en el que una aplicación web malintencionada puede influir en la interacción entre un explorador cliente y una aplicación web que confía en ese explorador. Estos ataques son posibles porque los exploradores web envían automáticamente algunos tipos de token de autenticación con cada solicitud en un sitio web. Esta forma de exploit también se conoce como ataque con un clic o secuestro de sesión porque el ataque aprovecha la sesión autenticada previamente del usuario.
Ejemplo de un ataque de CSRF:
Un usuario inicia sesión en
www.good-banking-site.example.comcon la autenticación de formularios. El servidor autentica al usuario y emite una respuesta que incluye una autenticación cookie. El sitio es vulnerable a ataques porque confía en cualquier solicitud que reciba con una cookie de autenticación válida.El usuario visita un sitio malintencionado,
www.bad-crook-site.example.com.El sitio malintencionado,
www.bad-crook-site.example.com, contiene un formulario HTML similar al ejemplo siguiente:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.example.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 el
actiondel formulario publica en el sitio vulnerable, no en el sitio malintencionado. Esta es la parte "entre sitios" de CSRF.El usuario selecciona el botón Enviar. El explorador realiza la solicitud e incluye automáticamente la cookie de autenticación para el dominio solicitado,
www.good-banking-site.example.com.La solicitud se ejecuta en el servidor de
www.good-banking-site.example.comcon el contexto de autenticación del usuario y puede realizar cualquier acción que un usuario autenticado pueda realizar.
Además del escenario en el que el usuario selecciona el botón para enviar el formulario, el sitio malintencionado podría:
- Ejecutar un script que envíe automáticamente el formulario.
- Enviar el envío del formulario como una solicitud AJAX.
- Ocultar el formulario mediante CSS.
Estos escenarios alternativos no requieren ninguna acción ni entrada por parte del usuario aparte de visitar inicialmente el sitio malintencionado.
El uso de HTTPS no impide un ataque de CSRF. El sitio malintencionado puede enviar https://www.good-banking-site.example.com/ una solicitud tan fácilmente como puede enviar una solicitud no segura.
Algunos ataques se dirigen a puntos de conexión que responden a solicitudes GET, en cuyo caso se puede usar una etiqueta de imagen para realizar la acción. Esta forma de ataque es común en sitios de foros que permiten imágenes pero bloquean JavaScript. Las aplicaciones que cambian el estado de las solicitudes GET, en las que se modifican variables o recursos, son vulnerables a ataques malintencionados. Las solicitudes GET que cambian de estado no son seguras. Un procedimiento recomendado es no cambiar nunca el estado en una solicitud GET.
Los ataques de CSRF se pueden producir en las aplicaciones web que usan cookies para la autenticación porque:
- Los exploradores almacenan cookies emitidas por una aplicación web.
- Las cookies almacenadas incluyen cookies de sesión para los usuarios autenticados.
- Los exploradores envían todas las cookies asociadas con un dominio a la aplicación web en cada solicitud independientemente de cómo se generó la solicitud a la aplicación en el explorador.
Sin embargo, los ataques CSRF no se limitan a aprovechar las vulnerabilidades de las cookies. Por ejemplo, la autenticación básica y Digest también son vulnerables. Una vez que un usuario inicia sesión con la autenticación básica o implícita, el explorador envía automáticamente las credenciales hasta que finaliza la sesión.
En este contexto, la sesión hace referencia a la sesión del lado cliente durante la cual se autentica el usuario. No está relacionado con las sesiones del servidor ni con el middleware de sesión de ASP.NET Core.
Para protegerse contra las vulnerabilidades de CSRF, los usuarios pueden tomar precauciones:
- Cierre la sesión de las aplicaciones web cuando termine de usarlas.
- Borra periódicamente las cookies del explorador.
Sin embargo, las vulnerabilidades de CSRF son fundamentalmente un problema con la aplicación web, no con el usuario final.
Aspectos básicos de la autenticación
La autenticación basada en Cookie es una forma popular de autenticación. Los sistemas de autenticación basados en tokens están creciendo en popularidad, especialmente para aplicaciones de página única (SPA).
Autenticación basada en Cookie
Cuando un usuario se autentica con su nombre de usuario y contraseña, se emite un token que contiene un vale de autenticación que se puede usar para la autenticación y la autorización. El token se almacena como una cookie que se envía con cada solicitud que realiza el cliente. La generación y validación de este cookie se realiza mediante el middleware de autenticación cookie. El middleware serializa una entidad de seguridad de usuario en una cookie cifrada. En las solicitudes posteriores, el middleware valida la cookie, vuelve a crear la entidad de seguridad y asigna la entidad de seguridad a la propiedad HttpContext.User.
Autenticación basada en tokens
Cuando se autentica un usuario, se emite un token (no un token de antifalsificación). El token contiene información de usuario en forma de notificaciones o un token de referencia que apunta la aplicación al estado de usuario mantenido en la aplicación. Cuando un usuario intenta acceder a un recurso que requiere autenticación, el token se envía a la aplicación con un encabezado de autorización adicional en forma de token de portador. Este enfoque hace que la aplicación no tenga estado. En cada solicitud posterior, el token se pasa en la solicitud de validación del lado servidor. Este token no está cifrado; está codificado. En el servidor, el token se descodifica para acceder a su información. Para enviar el token en solicitudes posteriores, almacene el token en el almacenamiento local del explorador. No se preocupe por la vulnerabilidad de CSRF si el token se almacena en el almacenamiento local del explorador. La CSRF es un problema cuando el token se almacena en una cookie. Para obtener más información, consulta el problema de GitHub El ejemplo de código SPA agrega dos cookies.
Varias aplicaciones hospedadas en un dominio
Los entornos de hospedaje compartidos son vulnerables al secuestro de sesión, a la CSRF de inicio de sesión y a otros ataques.
Aunque example1.contoso.net y example2.contoso.net son hosts diferentes, hay una relación de confianza implícita entre los hosts bajo el dominio *.contoso.net. Esta relación de confianza implícita permite que hosts que podrían no ser de confianza afecten a las cookies de otros hosts (las directivas de mismo origen que rigen las solicitudes AJAX no se aplican necesariamente a las cookies HTTP).
Los ataques que aprovechan las cookies de confianza entre aplicaciones hospedadas en el mismo dominio pueden evitarse si no se comparten dominios. Cuando cada aplicación se hospeda en su propio dominio, no hay ninguna relación de confianza implícita que se pueda aprovechar.
Configuración de la antifalsificación de ASP.NET Core
Advertencia
ASP.NET Core implementa la antifalsificación mediante la Protección de datos de ASP.NET Core. La pila de protección de datos debe configurarse para que funcione en una granja de servidores. Para obtener más información, consulte Configuración de la protección de datos.
El middleware de antifalsificación se agrega al contenedor de inserción de dependencias cuando se llama a una de las siguientes API en Startup.ConfigureServices:
En ASP.NET Core 2.0 o posterior, el elemento FormTagHelper inserta tokens de antifalsificación en los elementos de formulario HTML. El siguiente marcado en un archivo de Razor genera automáticamente tokens de antifalsificación:
<form method="post">
...
</form>
De forma similar, IHtmlHelper.BeginForm genera tokens antifalsificación de forma predeterminada si el método del formulario no es GET.
La generación automática de tokens de antifalsificación para elementos de formulario HTML se produce cuando la etiqueta <form> contiene el atributo method="post" y se cumple alguna de las siguientes condiciones:
- El atributo action está vacío (
action=""). - El atributo action no se proporciona (
<form method="post">).
La generación automática de tokens de antifalsificación para elementos de formulario HTML se puede deshabilitar:
Deshabilite explícitamente los tokens de antifalsificación con el atributo
asp-antiforgery.<form method="post" asp-antiforgery="false"> ... </form>El elemento de formulario se ha excluido de los asistentes de etiquetas mediante el símbolo de rechazo ! del asistente de etiquetas:
<!form method="post"> ... </!form>Quite
FormTagHelperde la vista.FormTagHelperpuede eliminarse de una vista mediante la adición de la siguiente directiva a la vista Razor.@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Nota:
Las Razor páginas están protegidas automáticamente contra XSRF/CSRF. Para obtener más información, vea XSRF/CSRF y Razor Pages.
El enfoque más común para defenderse contra ataques de CSRF es usar el patrón de token del sincronizador (STP). El STP se usa cuando el usuario solicita una página con datos de formulario:
- El servidor envía un token asociado a la identidad del usuario actual al cliente.
- El cliente devuelve el token al servidor para su comprobación.
- Si el servidor recibe un token que no coincide con la identidad del usuario autenticado, se rechaza la solicitud.
El token es único e imprevisible. El token también se puede usar para garantizar la secuenciación correcta de una serie de solicitudes (por ejemplo, garantizar la secuencia de solicitudes de: página 1 > página 2 > página 3). Todos los formularios de las plantillas de Razor Pages y de ASP.NET Core MVC generan tokens de antifalsificación. El siguiente par de ejemplos de vista genera tokens de antifalsificación:
<form asp-controller="Todo" asp-action="Create" method="post">
...
</form>
@using (Html.BeginForm("Create", "Todo"))
{
...
}
Agregue explícitamente un token de antifalsificación a un elemento <form> sin usar asistentes de etiquetas con el asistente de HTML @Html.AntiForgeryToken:
<form action="/" method="post">
@Html.AntiForgeryToken()
</form>
En cada uno de los casos anteriores, ASP.NET Core agrega un campo de formulario oculto similar al ejemplo siguiente:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core incluye tres filtros para trabajar con tokens de antifalsificación:
Opciones de antifalsificación
Personalización de AntiforgeryOptions en Startup.ConfigureServices:
services.AddAntiforgery(options =>
{
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Establezca las propiedades de la cookie de antifalsificación mediante las propiedades de la clase CookieBuilder, como se muestra en la tabla siguiente.
| Opción | Descripción |
|---|---|
| Cookie | Determina la configuración usada para crear las cookies de antifalsificación. |
| FormFieldName | Nombre del campo de formulario oculto utilizado por el sistema de antifalsificación para representar tokens de antifalsificación en vistas. |
| HeaderName | Nombre del encabezado utilizado por el sistema de antifalsificación. Si es null, el sistema solo tiene en cuenta los datos del formulario. |
| SuppressXFrameOptionsHeader | Especifica si se va a suprimir la generación del encabezado X-Frame-Options. De forma predeterminada, el encabezado se genera con un valor de "SAMEORIGIN". Tiene como valor predeterminado false. |
Algunos exploradores no permiten que los puntos de conexión inseguros establezcan cookies con una marca "segura" o sobrescribir cookies cuya marca "segura" está establecida (para obtener más información, consulte Desuso de la modificación de cookies "seguras" de orígenes no seguros). Dado que la combinación de puntos de conexión seguros e inseguros es un escenario común en las aplicaciones, ASP.NET Core relaja la restricción de la directiva segura en algunas cookies, como la antifalsificación cookie, estableciendo el cookie de SecurePolicy en CookieSecurePolicy.None. Incluso si un usuario malintencionado roba un elemento de antifalsificación cookie, también debe robar el token de antifalsificación que normalmente se envía a través de un campo de formulario (más común) o de un encabezado de solicitud independiente (menos común), además de la autenticación cookie. Las cookies relacionadas con la autenticación o autorización usan una directiva más fuerte que CookieSecurePolicy.None.
Si lo deseas, puedes proteger el mecanismo antifalsificación cookie en entornos que no sean Development mediante el protocolo Secure Sockets Layer (SSL), únicamente a través de HTTPS, con la siguiente configuración de la propiedad AntiforgeryOptions.Cookie en la clase Startup de la aplicación:
public class Startup
{
public Startup(IConfiguration configuration, IHostEnvironment environment)
{
Configuration = configuration;
Environment = environment;
}
public IConfiguration Configuration { get; }
public IHostEnvironment Environment { get; }
public void ConfigureServices(IServiceCollection services)
{
// Other services are registered here
if (!Environment.IsDevelopment())
{
services.AddAntiforgery(o =>
{
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
}
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Request processing pipeline
}
}
Para obtener más información, vea CookieAuthenticationOptions.
Configuración de características de antifalsificación con IAntiforgery
IAntiforgeryproporciona la API para configurar características de antifalsificación.
IAntiforgery se puede solicitar en el método Configure de la clase Startup.
En el ejemplo siguiente:
- Se usa middleware de la página principal de la aplicación para generar un token de antifalsificación y enviarlo en la respuesta como cookie.
- El token de solicitud se envía como una cookie legible en JavaScript con la convención de nomenclatura de Angular predeterminada que se describe en la sección 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);
});
}
Requerir validación de antifalsificación
ValidateAntiForgeryToken es un filtro de acción que se puede aplicar a una acción individual, un controlador o globalmente. Las solicitudes realizadas a las acciones que tienen aplicado este filtro se bloquean a menos que la solicitud incluya un token de antifalsificación 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 });
}
El atributo ValidateAntiForgeryToken requiere un token para las solicitudes a los métodos de acción que marca, incluidas las solicitudes HTTP GET. Si el atributo ValidateAntiForgeryToken se aplica en los controladores de la aplicación, se puede invalidar con el atributo IgnoreAntiforgeryToken.
Nota:
ASP.NET Core no admite la adición automática de tokens de antifalsificación a las solicitudes GET.
Validar automáticamente tokens de antifalsificación solo para métodos HTTP no seguros
Las aplicaciones de ASP.NET Core no generan tokens de antifalsificación para métodos HTTP seguros (GET, HEAD, OPTIONS y TRACE). En lugar de aplicar ampliamente el atributo ValidateAntiForgeryToken y, a continuación, reemplazarlo con atributos IgnoreAntiforgeryToken, se puede usar el atributo AutoValidateAntiforgeryToken. Este atributo funciona de forma idéntica al atributo ValidateAntiForgeryToken, salvo que no requiere tokens para las solicitudes realizadas mediante los siguientes métodos HTTP:
- GET
- HEAD
- Opciones
- TRACE
Se recomienda usar ampliamente AutoValidateAntiforgeryToken para escenarios que no son de API. Este atributo garantiza que las acciones POST estén protegidas de forma predeterminada. La alternativa es omitir los tokens de antifalsificación de forma predeterminada, a menos que ValidateAntiForgeryToken se aplique a métodos de acción individuales. Es más probable que en este escenario un método de acción POST se deje desprotegido por error, lo que hace que la aplicación sea vulnerable a los ataques de CSRF. Todos los POST deben enviar el token de antifalsificación.
Las API no tienen un mecanismo automático para enviar la parte del token que no es una cookie. La implementación probablemente depende de la implementación del código de cliente. A continuación se muestran algunos ejemplos:
Ejemplo de nivel de clase:
[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{
Ejemplo global:
services.AddControllersWithViews(options =>
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));
Invalidación de atributos de antifalsificación globales o de controlador
El filtro IgnoreAntiforgeryToken se usa para evitar tener que usar un token de antifalsificación para una acción determinada (o controlador). Cuando se aplica, este filtro invalida los filtros ValidateAntiForgeryToken y AutoValidateAntiforgeryToken especificados en un nivel superior (global o en un controlador).
[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{
[HttpPost]
[IgnoreAntiforgeryToken]
public async Task<IActionResult> DoSomethingSafe(SomeViewModel model)
{
// no antiforgery token required
}
}
Actualización de tokens después de la autenticación
Los tokens se deben actualizar después de que el usuario se autentique al redirigir al usuario a una vista o página de Razor Pages.
JavaScript, AJAX y SPA
En las aplicaciones tradicionales basadas en HTML, los tokens de antifalsificación se pasan al servidor mediante campos de formulario ocultos. En las aplicaciones y SPA modernas basadas en JavaScript, muchas solicitudes se realizan mediante programación. Estas solicitudes de AJAX pueden usar otras técnicas (como encabezados de solicitud o cookies) para enviar el token.
Si se usan cookies para almacenar tokens de autenticación y para autenticar solicitudes de API en el servidor, la CSRF es un posible problema. Si el almacenamiento local se usa para almacenar el token, se podría mitigar la vulnerabilidad de CSRF porque los valores del almacenamiento local no se envían automáticamente al servidor con cada solicitud. El uso del almacenamiento local para almacenar el token de antifalsificación en el cliente y enviar el token como encabezado de solicitud es un enfoque recomendado.
JavaScript
Al usar JavaScript con vistas, el token se puede crear mediante un servicio desde dentro de la vista. Inserte el servicio IAntiforgery en la vista y luego llame a 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>
Este enfoque evita tener que tratar directamente con la configuración de cookies del servidor o leerlas del cliente.
En el ejemplo anterior se usa JavaScript para leer el valor de campo oculto del encabezado POST de AJAX.
JavaScript también puede acceder a tokens en cookies y usar el contenido de la cookie para crear un encabezado con el valor del token.
context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken,
new Microsoft.AspNetCore.Http.CookieOptions { HttpOnly = false });
Suponiendo que el script solicita enviar el token en un encabezado denominado X-CSRF-TOKEN, configure el servicio de antifalsificación para buscar el encabezado X-CSRF-TOKEN:
services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN");
En el ejemplo siguiente se usa JavaScript para realizar una solicitud de AJAX con el encabezado adecuado:
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 una convención para abordar la CSRF. Si el servidor envía un cookie con el nombre XSRF-TOKEN, el servicio $http de AngularJS añade el valor cookie a un encabezado al enviar una solicitud al servidor. Este es un proceso automático. El cliente no necesita establecer el encabezado explícitamente. El nombre del encabezado es X-XSRF-TOKEN. El servidor debe detectar este encabezado y validar su contenido.
Para que la API de ASP.NET Core funcione con esta convención en el inicio de la aplicación:
- Configure la aplicación para proporcionar un token en una cookie denominada
XSRF-TOKEN. - Configure el servicio de antifalsificación para buscar un encabezado denominado
X-XSRF-TOKEN, que es el nombre de encabezado predeterminado de Angular para enviar el 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");
}
Nota:
Cuando el token antifalsificación se proporciona tanto en la cabecera de la solicitud como en la carga útil del formulario, sólo se valida el token de la cabecera.
Autenticación de Windows y cookies antifalsificación
Al usar la autenticación de Windows, los puntos de conexión de la aplicación deben protegerse frente a ataques de CSRF de la misma manera que se hace para las cookies. El explorador envía implícitamente el contexto de autenticación al servidor y, por tanto, los puntos de conexión deben protegerse frente a ataques de CSRF.
Extensión de la antifalsificación
El tipo IAntiforgeryAdditionalDataProvider permite a los desarrolladores ampliar el comportamiento del sistema anti-CSRF mediante el recorrido de ida y vuelta de datos adicionales en cada token. Se llama al método GetAdditionalData cada vez que se genera un token de campo; el valor devuelto se inserta dentro del token generado. Un implementador podría devolver una marca de tiempo, un valor nonce o cualquier otro valor y, a continuación, llamar a ValidateAdditionalData para validar estos datos cuando se valida el token. El nombre de usuario del cliente ya está insertado en los tokens generados, por lo que no es necesario incluir esta información. Si un token incluye datos complementarios pero no se configura un IAntiForgeryAdditionalDataProvider, los datos complementarios no se validan.