asp.net-mvc - bootstrap - desarrollo web con asp.net core 2 mvc
¿Por qué se produce HttpAntiForgeryException al azar incluso con una clave de máquina estática? (5)
El token anti falsificación contiene el nombre de usuario del usuario conectado actualmente cuando se emite. Y al verificar su validez, el usuario conectado actualmente se compara con el utilizado cuando se emitió el token. Así, por ejemplo, si tiene un formulario en el que el usuario aún no está autenticado y emite un token antirrobo, no habrá ningún nombre de usuario almacenado en él. Si cuando envía el formulario autentica al usuario, el token ya no será válido. Lo mismo se aplica para cerrar sesión.
Así es como se ve el método Validar:
public void Validate(HttpContextBase context, string salt)
{
string antiForgeryTokenName = AntiForgeryData.GetAntiForgeryTokenName(null);
string str2 = AntiForgeryData.GetAntiForgeryTokenName(context.Request.ApplicationPath);
HttpCookie cookie = context.Request.Cookies[str2];
if ((cookie == null) || string.IsNullOrEmpty(cookie.Value))
{
throw CreateValidationException();
}
AntiForgeryData data = this.Serializer.Deserialize(cookie.Value);
string str3 = context.Request.Form[antiForgeryTokenName];
if (string.IsNullOrEmpty(str3))
{
throw CreateValidationException();
}
AntiForgeryData data2 = this.Serializer.Deserialize(str3);
if (!string.Equals(data.Value, data2.Value, StringComparison.Ordinal))
{
throw CreateValidationException();
}
string username = AntiForgeryData.GetUsername(context.User);
if (!string.Equals(data2.Username, username, StringComparison.OrdinalIgnoreCase))
{
throw CreateValidationException();
}
if (!string.Equals(salt ?? string.Empty, data2.Salt, StringComparison.Ordinal))
{
throw CreateValidationException();
}
}
Una posible forma de depurar esto es volver a compilar ASP.NET MVC desde su código fuente y registrar exactamente en cuál de los casos se ingresa cuando se produce la excepción.
Tenemos una aplicación ASP.NET MVC 2 (.NET 4) que se ejecuta en Windows Azure (la última versión del sistema operativo 2.x) con dos instancias de rol web.
Utilizamos el token anti-falsificación suministrado por MVC para todas las solicitudes POST, y hemos establecido una Clave de la máquina estática en web.config, por lo que todo funciona en varias máquinas y en reinicios. El 99,9% de los casos funciona perfectamente.
De vez en cuando, sin embargo, registramos una HttpAntiForgeryException, con el mensaje "No se proporcionó un token anti-falsificación requerido o no fue válido".
Sé que el problema podría ser que no se permiten las cookies en el navegador, pero hemos verificado que las cookies están habilitadas y se envían de un lado a otro correctamente.
El error ocurre con una variedad de navegadores y obviamente causa problemas a los usuarios porque tienen que repetir la operación o pueden perder algunos datos. Basta con decir que no hemos podido reproducir el problema localmente, pero solo sucede en Windows Azure.
¿Por qué está sucediendo eso? ¿Cómo podemos evitarlo?
Hay un par de opciones para lo que podrías probar. Puede probar la comunicación remota en la máquina y mirar el registro de eventos para ver si puede obtener más información acerca de dónde está sucediendo esto. Si eso no ayuda, puede usar DebugDiag o alguna otra herramienta para capturar un volcado del proceso (DebugDiag le permitirá capturar una en el momento de esta excepción específica). Y luego mira eso para ver qué está pasando.
Si parece que no puede resolverlo a partir de ahí, siempre puede crear un caso de soporte con Microsoft para ayudarlo a investigarlo.
Me encontré con esto recientemente también y encontré dos causas.
1. El navegador restaura la última sesión en la página abierta que está en caché
Si tiene una página que se puede almacenar en la memoria caché que realiza una publicación en su servidor (es decir, el antiforgery estará activado) y el usuario tiene su navegador configurado para restaurar la última sesión al inicio (esta opción existe en Chrome), la página se procesará desde la memoria caché. . Sin embargo, la cookie de verificación de solicitud no estará allí porque es una cookie de sesión del navegador y se descarta cuando se cierra el navegador. Como la cookie se ha ido, obtienes la excepción anti-falsificación. Solución: devuelva los encabezados de respuesta para que la página no se almacene en caché (es decir, Cache-Control: privado, no-store).
2. Condición de la carrera si abre más de una pestaña en el inicio de su sitio
Los navegadores tienen la opción de abrir un conjunto de pestañas en el inicio. Si más de uno de ellos llega a su sitio que devuelve una cookie de verificación de solicitud, puede alcanzar una condición de carrera en la que se sobrescribe la cookie de verificación de solicitud. Esto sucede porque más de una solicitud llega a su servidor de un usuario que no tiene configurada la cookie de verificación de solicitud. La primera solicitud se maneja y establece la cookie de verificación de solicitud. A continuación, se maneja la segunda solicitud, pero no envió la cookie (aún no se había configurado en el momento de la solicitud), por lo que el servidor genera una nueva. La nueva sobrescribe la primera y ahora esa página recibirá una excepción de solicitud de antiforgería la próxima vez que realice una publicación. El framework MVC no maneja este escenario. Este error ha sido reportado al equipo MVC en Microsoft.
Me he encontrado con problemas similares con mi código anti-falsificación de fabricación casera, que conceptualmente es muy similar al mecanismo MVC. El problema parece ocurrir principalmente porque los navegadores modernos parecen estar dispuestos a mostrar copias en caché de las páginas especificadas como no almacenadas en caché.
He intentado todas las combinaciones de directivas de no caché de páginas, pero a veces todavía se muestran páginas en caché.
Descubrí que una mejor solución es conectar el evento onbeforeunload para la página y borrar explícitamente el valor del campo de entrada oculto que contiene el valor del token en el DOM.
Si se carga una copia en caché de una página, parece que contiene el valor del campo de entrada borrado. Luego pruebo esto en la función de documento preparado y recargo la página si es necesario:
window.location.reload(true);
Parece funcionar bastante bien, y sospecho que también podría serlo para el código anti-falsificación MVC.
Tengo algunas aplicaciones web de MVC3 que también lo obtienen con bastante frecuencia. La mayoría de ellos se debe a que el cliente no envía un cuerpo POST. Y la mayoría de estos son IE8 debido a algún error con las solicitudes de ajax que preceden a una publicación de formulario regular. Hay una revisión para IE que parece abordar los síntomas, lo que demuestra que es un error del cliente en estos casos
http://support.microsoft.com/?kbid=831167
Hay algunas discusiones sobre el tema en la web, pero no es demasiado útil, definitivamente no estoy dispuesto a meterme con los tiempos de espera para mantener vivo, lo cual es una "solución" sugerida en algunos lugares ...
https://www.google.com/search?q=ie8+empty+post+body
Nunca he podido reproducirlo con una variedad de intentos para restablecer las conexiones entre POSTS, así que me temo que no tengo una solución real para el caso de los cuerpos POST vacíos de IE. La forma en que lo hemos mitigado un poco es asegurarnos de que nunca usamos el método POST cuando solo recuperamos datos a través de ajax.
Si registra la solicitud completa, verifique si el cuerpo de la POST está vacío, y si lo está, probablemente será un IE más antiguo. Y no me refiero a Content-Length: 0, generalmente tendrá una Content-Length que parece correcta en los encabezados, pero literalmente no habrá nada después de los encabezados en la solicitud.
Sin embargo, el problema en su conjunto sigue siendo un misterio para mí porque aún tenemos la excepción ocasional de que existe un cuerpo POST completo. Nuestros nombres de usuario nunca cambian y nuestras claves también son estáticas, no he intentado agregar la depuración a la fuente, si alguna vez llego a eso, informaré mis hallazgos.