Hace unas semanas Microsoft anunció la revisión 4.5.2 de .NET, que actualiza un poco la última versión de la plataforma .NET (la 4.5) con algunos ajustes y correcciones.

Si nos atenemos a lo que anunciaron en el blog oficial, e incluso en la lista de cambios del lanzamiento, no hay nada que llame la atención sobre un pequeño detalle que sin embargo es muy importante: han deshabilitado la posibilidad de desactivar el MAC del ViewState en ASP.NET Web Forms.

Y esto ¿qué significa?

Para verlo, primero demos un repaso rápido a qué es el MAC y para qué sirve. Luego veremos qué implicaciones tiene el hecho de no poder desactivarlo.

Funcionamiento del ViewState y autenticación

SeguridadWebEl ViewState, como todos deberíamos saber, es una parte fundamental del funcionamiento de Web Forms. Almacena el estado de los diferentes controles de una página entre postbacks.

En Web Forms cada evento que se produce que se gestiona en el servidor implica un envío de la página de nuevo al servidor. A estos reenvíos se les conoce como PostBack. El servidor gestiona el evento (por ejemplo el clic de un botón) pero antes reconstruye el estado de todos los controles de la página para saber cómo se enviaron al cliente. De este modo es posible mantener todo como estaba, incluso en controles muy complejos como una rejilla, en cada ida y vuelta entre cliente y servidor, aunque se produzcan muchas veces en la misma página. Este "truco", aunque carga las páginas más de la cuenta, es muy efectivo y es la clave de que sea tan fácil programar con ASP.NET Web Forms.

El problema del ViewState es que, si alguien lo cambiase en el navegador antes de enviarlo de vuelta al servidor, podría engañar a la aplicación metiendo cualquier valor inapropiado en los controles. Por ejemplo, imagina una tienda on-line en la que un atacante cambiase los precios a su antojo. Dado que el ViewState se puede enviar al cliente sin encriptar (simplemente codificado como Base64), es muy fácil decodificarlo, modificarlo y volver a ponerlo con los cambios que queramos. En el peor de los casos un atacante hasta podría llegar a tomar el control de nuestro servidor.

Para evitar que esto ocurra, por defecto, ASP.NET Web Forms utiliza lo que se conoce como una verificación de autenticación de máquina o Machine Authentication Check (MAC). Básicamente el MAC consiste en agregar al final del ViewState un resumen digital o hash de los contenidos del mismo, encriptado usando una clave privada que solo conoce el servidor. Si al recibir de nuevo el ViewState tras un postback alguien hubiese cambiado los contenidos, sería muy fácil de detectar comprobando esa información cifrada y viendo que no coincide con la que se esperaría para ese contenido.

Es más fácil entenderlo si lo vemos paso a paso:

  1. El usuario solicita una página .aspx
  2. El servidor genera la página a partir de sus controles y lógica. Antes de enviarla:
    1. Calcula el ViewState a partir del estado de los controles.
    2. Calcula el hash del ViewState.
    3. Cifra este hash con una clave privada que solo conoce el servidor (está guardad en un archivo de configuración global y es diferente para cada máquina)
    4. Añade el hash cifrado al final del ViewState, como una información extra.
    5. Se envía la página al navegador.
  3. La página se recibe en el navegador. El usuario interacciona con ella y provoca un evento de servidor pulsando en algún botón u otro control. Se envía de nuevo la página al servidor, adjuntando entre otras cosas el ViewState original.
  4. El servidor recibe la petición para manejar el evento:
    1. Carga el ViewState que se le está enviando y lo descodifica. Obtiene por tanto los valores que supuestamente tienen los controles de la página.
    2. Calcula el hash del ViewState que se le ha enviado y lo cifra.
    3. Compara el hash cifrado con el que viene adjunto al final del ViewState. Si coinciden es que el ViewState no ha sido modificado y se sigue con el procesamiento de la página. Si no coinciden, alguien ha estado toqueteando la página y se genera una excepción de seguridad.
  5. El proceso comienza de nuevo desde el paso 2.

Este proceso aparentemente complejo, en realidad es muy rápido y sencillo de realizar por lo que apenas impacta en el rendimiento de la página, pero nos añade una característica indispensable de seguridad.

Cuando se detecta un MAC inválido porque alguien ha estado tocando los valores antes de enviarlos de nuevo al servidor, recibiremos un error como el de la siguiente figura:

Error-Mac-ViewState

Error de servidor en la aplicación "La información de estado para esta página no es válida y puede haberse corrompido"

Es un error feo que podemos poner bonito con las características de errores personalizados de ASP.NET, y que en cualquier caso impedirá ataques a nuestras aplicaciones ASP.NET Web Forms, así que bienvenido sea :-)

Desactivando el MAC

No existen muchas razones, aparte de la ignorancia o la vagancia, para querer desactivar el control MAC de una aplicación ASP.NET Web Forms. La más habitual es que tengamos una aplicación con muchos usuarios, que va a trabajar dentro de una granja de servidores (Web Farm). Al ser máquinas diferentes las que gestionan las peticiones, salvo que montemos el sistema con afinidad, un postback puede llegar a una máquina diferente de la que originó la página inicialmente. Dado que cada máquina tiene por defecto una clave de cifrado para el MAC diferente, la comprobación fallaría y se produciría el error.

En estos casos detectar el error puede ser complejo ya que en la máquina de desarrollador funcionaría siempre bien, y en producción fallaría de vez en cuando solamente: cuando un postback de una página se recibiera en una máquina diferente. Mientras se recibiese en la misma no nos enteraríamos.

Obviamente la solución es establecer la misma clave de cifrado de MAC en todas las máquinas de la granja. Tan simple como esto. Está explicado con detalle en este artículo de la Knowledge Base de Microsoft.

Sin embargo muchos programadores en lugar de hacer eso, bien por desconocimiento o bien por vagancia (que es mucho peor) simplemente desconectaban el MAC de las páginas usando para ello la propiedad EnableViewStateMac:

EnableViewStateMac-Desactivar

que también se puede deshabilitar para la aplicación completa desde web.config.

Esto hace que las aplicaciones funcionen en granjas de servidores mal configuradas, pero es una barbaridad tremenda desde el punto de vista de la seguridad. Así que nunca jamás deberías utilizar ese ajuste en tus aplicaciones. Punto.

De hecho, en mi opinión Microsoft jamás debería haber sacado la propiedad EnableViewStateMac y dejar que nadie pudiera desactivar esta característica.

¡La propiedad ya no funciona!

Con esta última actualización de .NET 4.5.2, uno de los cambios que han pasado prácticamente inadvertidos es precisamente este: la propiedad EnableViewStateMac sigue siendo soportada y no dará error si la usamos, pero se hará caso omiso de ella y siempre se considerará que vale "true" independientemente de que establezca "false" como su valor, tanto en páginas individuales como para toda la aplicación.

Es decir, en la práctica es como si ya no existiese.

El verdadero problema no es que hayan tomado esta decisión, sino que no la hubieran tomado mucho antes; de hecho desde el primer momento, y nunca hubieran sacado esta infame propiedad.

Microsoft lo notificó a través de un post en el blog del equipo de desarrollo de .NET y lo resaltó muy clarito:

EnableViewStateMac-Nota-Blog

La verdad es que tiene gracia cómo lo expresan ;-)

La cuestión es que si tu aplicación dependía de este ajuste para funcionar, empezará a darte problemas -si no lo está haciendo ya- en cuanto la actualices a ASP.NET 4.5.2, cosa que podría ocurrir con cualquier actualización automática del servidor.

El principal problema será el de la granja de servidores, así que vete leyéndote el artículo de la KB reseñado más arriba y manos a la obra ya (¡¡la vagancia es muy mala!!). En el anuncio original de este cambio se explican algunas otras casuísticas que podrían darse.

¡Avisado quedas!

💪🏻 ¿Este post te ha ayudado?, ¿has aprendido algo nuevo?
Pues NO te pido que me invites a un café... Te pido algo más fácil y mucho mejor

Escrito por un humano, no por una IA