2012-03-29 7 views
15

Tenemos una aplicación ASP.NET MVC 2 (.NET 4) que se ejecuta en Windows Azure (última versión del sistema operativo 2.x) con dos instancias de rol web.¿Por qué HttpAntiForgeryException ocurre aleatoriamente incluso con una clave de máquina estática?

Utilizamos el token antifalsificación suministrado por MVC para todas las solicitudes POST, y hemos establecido una clave de máquina estática en web.config, por lo que todo funciona en varias máquinas y en reinicios. 99.9% de los casos funciona a la perfección.

De vez en cuando, sin embargo, registramos una HttpAntiForgeryException, con el mensaje "No se proporcionó un token antifalsificación requerido o no fue válido".

Sé que es posible que no se permitan las cookies en el navegador, pero hemos verificado que las cookies están habilitadas y se envían y reciben 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. Baste decir que no hemos podido reproducir el problema localmente, pero solo ocurre en Windows Azure.

¿Por qué está sucediendo eso? ¿Cómo podemos evitarlo?

+0

Comprobé con los chicos de seguridad (en el equipo de MVC) y Darin probablemente tenga razón, el nombre de usuario probablemente haya cambiado. – RickAndMSFT

Respuesta

0

Hay un par de opciones para lo que podrías probar. Podría tratar de establecer una conexión remota en la máquina y mirar el registro de eventos para ver si puede obtener más información al respecto en lo que respecta a dónde está sucediendo esto. Si eso no ayuda, puede usar DebugDiag u otra herramienta para capturar un volcado del proceso (DebugDiag le permitirá capturar uno en el momento de esta excepción específica). Y luego mira eso para ver qué está pasando.

Si parece que no puede resolverlo desde allí, siempre puede crear un caso de soporte con Microsoft para ayudarlo a investigarlo.

7

El token anti falsificación contiene el nombre de usuario del usuario actualmente conectado cuando se emite. Y al verificar su validez, el usuario actualmente conectado se compara con el utilizado cuando se emitió el token. Entonces, por ejemplo, si tiene un formulario en el cual el usuario aún no está autenticado y usted emite un token anti falsificación, no habrá ningún nombre de usuario almacenado en él. Si al enviar el formulario autentica al usuario, el token ya no será válido. Lo mismo se aplica para cerrar la sesión.

Así es como el método Validar parece:

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 este es recompilar ASP.NET MVC desde su código fuente y registrar exactamente en cuál de los casos si se introduce cuando la excepción es aventado.

+0

Los chicos de seguridad del equipo ASP.NET MVC están de acuerdo, el nombre de usuario probablemente haya cambiado. Ahora que MVC es de código abierto, puedes construir una rama diagnoística. Una nota menor, La ficha de AF NO contiene el nombre de usuario: el código muestra que el nombre de usuario proviene del token de formulario, no del token de cookie. – RickAndMSFT

+0

El problema es que no utilizamos la autenticación ASP.NET y nunca configuramos el usuario/identidad. ¿Puede el nombre de usuario cambiar por sí mismo (siempre que la aplicación se ejecute como Servicio de red en Azure)? –

+0

¿Intentó recompilar ASP.NET MVC desde el código fuente y el rastreo en cuyo caso falla la verificación antiforgery? –

15

Me encontré con esto recientemente también y encontré dos causas.

1. Navegador restaura la última sesión sobre abierto para que la página se almacena en caché

Si usted tiene una página que está cachable que realiza una entrada en tu servidor (es decir antiforgery será activado) y el usuario tiene a 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. Dado que la cookie se ha ido, obtienes la excepción antifalsificación. Solución: devuelva los encabezados de respuesta para que la página no se almacene en caché (es decir, Cache-Control: private, no-store).

2.Condición de carrera si se 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 al inicio. Si más de uno de ellos acierta en su sitio que devuelve una cookie de verificación de solicitud, puede golpear una condición de carrera donde se sobrescribe la cookie de verificación de solicitud. Esto sucede porque más de una solicitud llega a su servidor desde un usuario que no tiene la cookie de verificación de solicitud establecida. La primera solicitud se maneja y establece la cookie de verificación de solicitud. A continuación, se procesa la segunda solicitud, pero no se envió la cookie (no se había establecido todavía en el momento de la solicitud), por lo que el servidor genera una nueva. El nuevo sobrescribe el primero y ahora esa página recibirá una excepción de solicitud antifurrante cuando vuelva a realizar una publicación. El framework MVC no maneja este escenario. Este error ha sido reportado al equipo de MVC en Microsoft.

+0

Estoy viendo la condición 2 también. Solo le sucede al primer usuario. Una vez que la página se ha cargado para ese primer usuario, ya no sucede. – GnomeCubed

1

Tengo algunas aplicaciones web de MVC3 que también lo hacen 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 ajax que preceden a una publicación de formulario regular. Hay una revisión para IE que parece hacer frente a los síntomas, que tipo de prueba que es un error del cliente en estos casos

http://support.microsoft.com/?kbid=831167

Hay algunas discusiones sobre el tema en la web, nada demasiado útil, aunque , definitivamente no estoy a punto de meterse con los tiempos de espera de mantenimiento de conexión que es una "solución" se sugiere en algunos lugares ...

https://www.google.com/search?q=ie8+empty+post+body

nunca he sido capaz de reproducirla con una variedad de intentos de restablecer las conexiones entre los POSTS, así que me temo que no tengo un verdadero solución para el caso de los cuerpos de POST vacíos de IE. La forma en que lo hemos mitigado un poco es asegurarnos de que nunca usemos el método POST cuando solo recuperamos datos a través de ajax.

Si registra la solicitud completa, verifique si el cuerpo 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á un Content-Length que parece correcto en los encabezados, pero literalmente no habrá nada después de los encabezados en la solicitud.

El problema en su conjunto sigue siendo un misterio para mí, porque todavía tenemos la excepción ocasional de que hay 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.

0

He encontrado problemas similares con mi código antifalsificación hecho en casa, que es conceptualmente muy similar al mecanismo MVC. En su mayoría, el problema parece ocurrir porque los navegadores modernos parecen 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ágina, pero a veces sigo obteniendo páginas en caché.

He encontrado 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. entonces prueba para esto en la función de lista de documentos y recargar la página si es necesario:

window.location.reload(true); 

parece funcionar bastante efectiva, y yo sospecho que puede para el código anti-falsificación MVC también.

Cuestiones relacionadas