Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. ASP.NET
Code

Previniendo XSS en ASP.NET

by
Difficulty:BeginnerLength:LongLanguages:

Spanish (Español) translation by Ana Paulina Figueroa Vazquez (you can also view the original English article)

Muchos problemas de seguridad en los sitios web son ocasionados por la excesiva confianza en el usuario. La mayoría de los usuarios de tu aplicación web solamente harán lo que tengan la necesidad de hacer, mientras que un usuario curioso o malicioso a menudo querrá probar los límites del acceso. Es en esos límites cuando a menudo aparecen brechas en la seguridad de tu aplicación. He escrito acerca de la prevención de dos tipos comunes de vulnerabilidades con anterioridad, la inyección SQL y la falsificación de peticiones en sitios cruzados en aplicaciones ASP.NET. Este artículo se enfoca en la prevención del Cross Site Scripting, o secuencia de comandos en sitios cruzados, que es un tercer tipo común de vulnerabilidad en los sitios web.

Si bien un framework moderno hace mucho para que estos ataques se vuelvan más difíciles, creo que primero debemos comprender las maneras en las que una aplicación es vulnerable a un ataque. Primero veamos qué es Cross Site Scripting  y cómo puede ser explotado.

Qué es Cross Site Scripting

Cross Site Scripting (a menudo abreviado como XSS) permite la inyección de secuencias de comandos maliciosas en un sitio web que de otra forma sería confiable. Esta inyección ocurre sin el conocimiento del usuario. La secuencia de comandos inyectada se ejecuta como si viniera del sitio web original. De esa manera, la secuencia de comandos maliciosa puede acceder a cualquiera de los recursos del sitio web alojado a los que el usuario tendría acceso, como cookies o tokens de sesión.

La apertura para un ataque Cross Site Scripting ocurre cuando una aplicación web muestra la entrada de los usuarios o de recursos externos sin validarla ni codificarla apropiadamente. En la mayoría de los ataques Cross Site Scripting, el atacante intenta inyectar JavaScript a la página web de un servidor de confianza. El atacante también puede intentar inyectar HTML, Flash o cualquier otra cosa que el navegador ejecute. Sin importar cuál sea la secuencia de comandos, el objetivo sigue siendo lograr que el navegador ejecute el código elegido por el atacante.

Un ataque XSS persistido

Hay tres categorías de ataques Cross Site Scripting, divididas por el método de inyección y por el método para prevenir el ataque. En el primer tipo de ataque, la secuencia de comandos se almacena permanentemente en el servidor destino y, por lo tanto, se conoce como un ataque Cross Site Scripting persistido. Este ataque intenta incrustar la secuencia de comandos maliciosa en algo, por ejemplo la publicación de un foro almacenada en una base de datos, o en un campo aparentemente benigno, tal como la página de inicio de un usuario de la base de datos. Con la secuencia de comandos persistida, todos los visitantes del sitio que vean la publicación, el mensaje o cualquier elemento comprometido, se convierten en víctimas potenciales del ataque.

Los agresores que intentan este tipo de ataque generalmente se enfocan en campos de comentarios, foros, redes sociales y otros campos en los que se espera una entrada algo arbitraria por parte del usuario final y en donde ésto es una parte normal de la aplicación. El atacante puede incluir la secuencia de comandos dentro de una publicación en un foro como parte de una conversación que de otra forma sería válida. Cada vez que alguien vea la publicación, la secuencia de comandos será ejecutada.

Un ataque XSS reflejado

En el segundo tipo de ataque Cross Site Scripting, conocido como Cross Site Scripting reflejado, el atacante entrega la secuencia de comandos inyectada al sitio vulnerable para que sea devuelta inmediatamente al usuario. Entre los métodos comunes de hacer esto se encuentran las páginas atacadas en las que la entrada del usuario se vuelve parte de la salida de una página. Una página de búsqueda puede mostrar los términos de la búsqueda al usuario y puede proporcionar una vía para este ataque. La secuencia de comandos inyectada en la entrada de un usuario nunca debe ser almacenada por la aplicación web.

Ataques basados en DOM

El tercer ataque Cross Site Scripting ocurre completamente en el navegador. El ataque funciona a través de la manipulación del modelo interno de la página web dentro del navegador, conocido como DOM, y se conocen como ataques basados en DOM. De nuevo, estos permiten que el atacante ejecute código malicioso, pero el código devuelto por el servidor es manipulado para convertirlo en JavaScript ejecutable para la página web.

En última instancia, un ataque Cross Site Scripting es un ataque Cross Site Scripting, sin importar cómo se lleve a cabo. Dado que el código inyectado proviene de un servidor que de otra forma sería confiable, éste puede ejecutarse a menudo usando los permisos del sitio. Por lo tanto puede actuar como si fuera código nativo del sitio web.

Un ataque Cross Site Scripting exitoso puede permitir el acceso a las cookies en una página web. Estas cookies pueden contener información confidencial, incluyendo identificadores de sesión que permitirían que el atacante suplantara al usuario atacado. El ataque también puede cambiar el contenido HTML de una página para mostrar un formulario de inicio de sesión falso y así robar las credenciales de inicio de sesión del usuario. El atacante puede examinar y enviar cualquier tipo de contenido de la página, permitiendo la captura de información confidencial como números de cuentas. Un ataque más avanzado podría en efecto instalar un registrador de claves, o key logger, que envíe a un atacante toda la información introducida en una página web.

Protección contra los ataques Cross Site Scripting

Para mitigar los ataques Cross Site Scripting se requiere desconfiar de cualquier entrada del usuario o de cualquier otra fuente externa. La aplicación web debe tratar estos datos como potencialmente peligrosos sin importar la fuente. Veamos algunos métodos específicos de ASP.NET para prevenir estos ataques usando componentes integrados en el framework y bibliotecas disponibles de forma gratuita.

Valida todas las entradas

La aplicación web debe validar todas las entradas a la aplicación antes de usarlas. De la misma manera en la que ocurre con otros ataques por inyección, como la inyección SQL. De preferencia, la aplicación debe validar esta entrada usando una lista blanca de valores aceptables. La validación elimina o reemplaza cualquier componente inesperado en la entrada por un valor codificado. Es posible usar un método de lista negra, que solamente elimina una lista de caracteres no deseados conocidos, pero es más vulnerable a nuevos métodos de ataque.

Si sabemos que un valor siempre debe ser entero, entonces puedes validar la entrada usando código como el siguiente:

Si el framework no puede convertir el valor externalValue previamente obtenido a entero, el código redirige a una página que mostrará un error. De lo contrario sabemos que memberId contiene un valor entero. Este proceso también funciona con otros tipos básicos. Algunos tipos más comunes también proporcionan métodos para validar la información. la clase Uri de .NET contiene un método IsWellFormedUriString que puede validar un URL. Esto permitiría validar que la entrada correspondiente a la página de inicio de un usuario contenga un URL válido antes de mostrarla.

Otros tipos de datos más complejos necesitan una validación más compleja. La validación de un campo para número de tarjeta de crédito puede eliminar todos los caracteres de la cadena que no sean dígitos. La validación de cadenas más complejas podría requerir el uso de expresiones regulares. La validación de una clase también puede necesitar verificaciones más complejas.

Validación de solicitudes en ASP.NET

ASP.NET proporciona una protección efectiva contra ataques reflejados usando la validación de solicitudes. Si ASP.NET detecta marcado o código en una solicitud, éste lanza una excepción "un valor potencialmente peligroso fue detectado" y detiene el procesamiento de la solicitud.

Si bien esto es valioso, hay veces en las que necesitas permitir estos valores en una solicitud. Un ejemplo común es permitir la entrada de texto enriquecido en un formulario. Desafortunadamente, en estos casos la validación de solicitudes se desactiva muy a menudo para el sitio completo. Una mejor solución desactiva esta validación solamente cuando es necesario. En las versiones anteriores de ASP.NET, añadir validateRequest="false" a la directiva Page en Webforms desactivaría la validación para una página. En ASP.NET MVC, añadir el atributo [ValidateInput(false)] a una acción de un controlador desactiva la validación para esa acción, mientras que agregar el atributo [AllowHtml] desactiva la validación para un campo.

ASP.NET 4.0 cambió la validación de solicitudes de varias maneras Esta versión y las versiones posteriores del framework hacen la validación en una etapa temprana de la solicitud HTTP. La validación también aplica a todas las solicitudes ASP.NET y no solamente a las solicitudes de páginas .aspx. Esto incluye a los módulos HTTP personalizados también. Las páginas que dependen del comportamiento original pueden regresar al método anterior asignando la versión 2.0 al atributo requestValidationMode en el archivo web.config.

Es aún mejor desactivar esto solamente para las páginas cuando sea necesario mediante el uso de esta sintaxis en el archivo web.config:

ASP.NET 4.5 añadió la capacidad de aplazar la validación hasta solicitar los datos. Asignar la versión 4.5 al atributo requestValidationMode en tu archivo web.config activa este nuevo comportamiento.

ASP.NET 4.5 también añadió la propiedad HttpRequest.Unvalidated. El uso de esta propiedad permite un acceso más sencillo al valor del formulario no validado cuando sea necesario. Al combinar la validación retrasada y la propiedad Unvalidated, puedes acceder a los valores no validados cuando sea necesario, pero protegiendo a otras entradas del formulario.

Codificando HTML

Antes de desplegar datos externos en una página web, tu HTML debe ser codificado para que no sea procesado por el navegador. Como ejemplo, toma una página ASP.NET escrita de manera que un mensaje pueda ser enviado para visualizarlo, por ejemplo la actualización de un estado. Una aplicación puede usar esta página para mostrar al usuario que su cuenta ha sido creada sin errores. El URL para esta página normalmente se vería de forma similar a http://appname/placeorder/Account+Created. La página resultante muestra el mensaje al usuario con un campo, por ejemplo:

... y lo muestra de esta forma:

Si cambiamos la llamada del URL a http://appname/placeorder/<script>alert('hello!');</script>, ahora obtenemos algo diferente.

Desde luego, la secuencia de comandos puede ser cualquier cosa y no solamente el inofensivo cuadro de alerta que aparece aquí. La validación de solicitudes atraparía los ejemplos anteriores y devolvería una excepción antes de la visualización. Sin embargo, si se desactiva entonces la codificación de la salida previene el ataque.

ASP.NET vuelve sencilla la codificación de datos para prevenir ataques. Las versiones previas de MVC que usaban la sintaxis de Webform a menudo contenían código como este que no codificaba HTML.

Tenías que codificar la salida manualmente para que cualquier HTML pudiera ser convertido en un formato de visualización. Así el carácter < se convierte en la cadena &lt;. La función Html.Encode proporciona esta conversión. Por lo tanto, la forma más segura del código se convierte en lo siguiente:

Posteriormente ASP.NET MVC introdujo una sintaxis para hacer esto en un paso reemplazando <= con <:, de manera que el código pudiera reducirse a:

Usando el motor de visualización Razor, toda la salida es HTML codificado a menos que uses un método específicamente para no codificarla. En Razor, el código equivalente al anterior se convierte en el siguiente:

Razor gestiona la codificación HTML de lo que sea que la cadena status contenga automáticamente. En dado caso que necesites mostrar los datos en bruto, puedes usar el método HTML.Raw(). Para mostrar el resultado sin codificar, podemos usar:

En este ejemplo, el código anterior volvería vulnerable a nuestra aplicación nuevamente. Por lo tanto, hay algunas circunstancias en las que no debes codificar la salida. Si desactivas esta herramienta en un campo, debes tomar precauciones adicionales para asegurar que los datos estén desinfectados antes de mostrarlos. Afortunadamente hay una biblioteca que ayuda a hacer esto, además de hacer más para proteger a tu aplicación de Cross Site Scripting.

La biblioteca AntiXSS

Si estás codificando una aplicación ASP.NET, debes usar la biblioteca AntiXSS para ASP.NET. Según el sitio web del proyecto, "AntiXSS proporciona una miríada de funciones para la codificación de la entrada del usuario, incluyendo HTML, atributos HTML, XML, CSS y JavaScript".

La biblioteca contiene métodos enfocados en la desinfección de datos externos en base al uso previsto de esa información. Estos métodos usan el enfoque preferido basado en listas blancas. Esto significa que los datos codificados, destinados a un atributo HTML, pueden desinfectarse para que solamente contengan datos válidos para un atributo HTML. Los métodos tradicionales HtmlEncode de ASP.NET usan el enfoque de listas negras que solamente codifican ciertos caracteres potencialmente peligrosos.

Microsoft comenzó a incluir rutinas centrales de esta biblioteca en ASP.NET 4.5 a través de un nuevo espacio de nombres System.Web.Security.AntiXss. También puedes configurar el framework para usar estos métodos AntiXSS en lugar de las rutinas de codificación integradas. Puedes hacer esto configurando el atributo encoderType de httpRuntime en el archivo web.config para la aplicación:

Si tu aplicación despliega una cantidad significativa de datos externos, entonces el uso de AntiXSS hará mucho para proteger a tu aplicación de ataques Cross Site Scripting. Si usas ASP.NET 4.5, entonces modificar tu aplicación para que use los nuevos métodos AntiXSS para la codificación predeterminada proporcionará aún más protección para tu aplicación web.

En resumen

Prevenir Cross Site Scripting es más difícil de lo que parece inicialmente.  OWASP lista más de 80 vectores que pueden ser blanco de ataques usando Cross Site Scripting. Esa organización también lista estas vulnerabilidades en el tercer lugar en su lista de las 10 principales vulnerabilidades del año 2013.

Si no te aseguras de que todos los datos externos introducidos en tu aplicación estén escapados correctamente o si no validas la entrada antes de colocarla en una página de salida, puedes ocasionar que tu aplicación web se vuelva vulnerable a los ataques Cross Site Scripting. En ASP.NET, esto puede lograrse a través de lo siguiente:

  1. Validando todas las entradas externas de tu aplicación antes de mostrarlas en una página web.
  2. Usando la validación de solicitudes en todos los lugares en los que tu aplicación no necesite desactivar dicha función de manera específica, como en el caso de un formulario que permita la entrada de HTML enriquecido. Si debes permitir información no validada, deja la validación activa en todos los puntos restantes de tu aplicación.
  3. Codifica el HTML antes de mostrar datos externos en una página web.
  4. Usa los métodos basados en AntiXSS incluídos en ASP.NET 4.5 y usa la biblioteca AntiXSS para versiones anteriores de ASP.NET.
Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.