Previniendo XSS en ASP.NET

Muchos problemas de seguridad de los sitios web provienen de confiar demasiado en el usuario. La mayoría de los usuarios de su aplicación web solo harán lo que tienen que hacer, un usuario curioso o malintencionado a menudo querrá ampliar los límites del acceso. En esos bordes, los agujeros de seguridad a menudo aparecen en su aplicación. He escrito sobre la prevención de dos tipos comunes de vulnerabilidades, la Inyección de SQL y la falsificación de solicitudes entre sitios, en aplicaciones ASP.NET anteriores. Este artículo analiza la prevención de secuencias de comandos entre sitios, un tercer tipo común de vulnerabilidad en los sitios web.

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

¿Qué es la secuencia de comandos de sitios cruzados

Los scripts de sitios cruzados (a menudo abreviados como XSS) permiten la inyección de scripts maliciosos en un sitio web confiable. Esta inyección ocurre sin el conocimiento del usuario. El script inyectado se ejecuta como si proviniera del sitio web original. Por lo tanto, el script malicioso puede acceder a cualquier recurso del sitio web alojado al que el usuario tendría acceso, como cookies o tokens de sesión..

La apertura para un ataque de scripts entre sitios se produce cuando una aplicación web muestra información de usuarios o recursos externos sin validarla o codificarla correctamente. En la mayoría de los ataques de scripts entre sitios, el atacante intenta inyectar JavaScript en la página web de un servidor de confianza. El atacante también puede intentar inyectar HTML, Flash o cualquier otra cosa que ejecute el navegador. No importa el script, el objetivo sigue siendo lograr que el navegador ejecute el código que elija el atacante..

Un ataque XSS persistente

Hay tres categorías de ataques de scripts entre sitios, divididos por el método de inyección y el método de prevención del ataque. En el primer tipo de ataque, la secuencia de comandos se almacena permanentemente en el servidor de destino y, por lo tanto, se denomina ataque de secuencias de comandos entre sitios persistente. Este ataque intenta incrustar el script malicioso en algo como una publicación del foro almacenada en una base de datos o un campo aparentemente benigno como la página de inicio de un usuario de la base de datos. Con la secuencia de comandos persistida, cada visitante del sitio que ve la publicación, el mensaje o un elemento comprometido, se convierte en una posible víctima del ataque..

Los atacantes que intentan este tipo de ataque generalmente se dirigen a los campos de comentarios, foros, redes sociales y otros campos en los que se espera una entrada algo arbitraria del usuario final y es una parte normal de la aplicación. El atacante puede incluir la secuencia de comandos en una publicación del foro en una parte válida de una conversación. Cada vez que alguien vea el post, se ejecutará el script..

Un ataque XSS reflejado

En el segundo tipo de ataque de scripts de sitios cruzados, conocido como script de sitios cruzados reflejado, el atacante entrega el script inyectado al sitio vulnerable para que se devuelva de inmediato al usuario. Los métodos comunes para hacer esto, las páginas de destino donde la entrada del usuario se convierte en parte de la salida de una página. Una página de búsqueda puede mostrar los términos de búsqueda al usuario y podría proporcionar una salida para este ataque. El script inyectado en la entrada de un usuario nunca debe ser almacenado por la aplicación web.

Ataques basados ​​en DOM

El tercer ataque de scripts entre sitios ocurre completamente en el navegador. Las funciones de ataque al manipular el modelo interno de la página web dentro del navegador conocido como DOM y se conocen como ataques basados ​​en DOM. Nuevamente, esto permite al atacante ejecutar código malicioso, pero el código devuelto por el servidor es manipulado en JavaScript ejecutable por la página web.

En última instancia, un ataque de secuencias de comandos entre sitios es un ataque de secuencias de comandos entre sitios, sin importar cómo se entregue. Dado que el código inyectado proviene de un servidor de otro modo confiable, a menudo puede ejecutarse bajo los permisos del sitio. Por lo tanto, puede actuar como si fuera un código nativo en el sitio web.. 

Un ataque exitoso de scripts entre sitios podría permitir el acceso a cookies en una página web. Estas cookies pueden contener información confidencial, incluidos identificadores de sesión que permitirían al atacante hacerse pasar por el usuario atacado. El ataque también puede cambiar el contenido HTML en una página para mostrar un formulario de inicio de sesión falso y robar las credenciales de inicio de sesión del usuario. El atacante podría examinar y enviar cualquier contenido de la página que permita la captura de información confidencial, como los números de cuenta. Un ataque más avanzado podría, en efecto, instalar un registrador de claves que envíe cualquier información ingresada en la página web a un atacante..

Protegiendo de los ataques de scripting entre sitios

La mitigación de las secuencias de comandos entre sitios requiere no confiar en ninguna entrada de un 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 evitar estos ataques utilizando componentes integrados en el marco y bibliotecas disponibles de forma gratuita.

Validar todas las entradas

La aplicación web debe validar cualquier entrada a la aplicación antes de que se utilice. Al igual que con otros ataques de inyección, como la inyección SQL. La aplicación preferiblemente valida esta entrada contra una lista blanca de valores aceptables. La validación elimina o reemplaza cualquier componente inesperado de la entrada con un valor codificado. Se puede usar un método de lista negra, que solo elimina una lista de caracteres no deseados conocidos, pero es más vulnerable a los nuevos métodos de ataque.

Si sabemos que un valor siempre debe ser un entero, entonces puede validar la entrada utilizando un código como:

int memberId; if (! int.TryParse (externalValue, out memberId)) return RedirectToAction ("InputError");  

Si el marco no puede analizar el recuperado anteriormente Valor externo como un entero, el código redirige a una página que mostraría un error. De lo contrario sabemos que Identificación de miembro 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 red Uri la clase contiene un método IsWellFormedUriString Eso puede validar una URL. Esto permitiría validar que la entrada de la página de inicio de un usuario contenga una URL válida antes de mostrarla.

var userHomePage = userRecord ["homepage"]; if (! Uri.IsWellFormedUriString (newUrl, UriKind.Absolute)) Model.homepage = "none";  else Model.homepage = Html.Encode (userHomePage);  

Otros tipos de datos más complejos necesitan una validación más compleja. La validación de un campo de número de tarjeta de crédito podría eliminar cualquier carácter de la cadena que no sea dígitos. La validación de cadenas más complejas podría necesitar expresiones regulares. La validación de una clase puede necesitar controles más complejos también.

Validación de la solicitud de ASP.NET

ASP.NET proporciona una protección eficaz contra los ataques reflejados mediante la validación de solicitudes. Si ASP.NET detecta marcas o códigos en una solicitud, arroja una excepción de "se detectó un valor potencialmente peligroso" y detiene el procesamiento de la solicitud.

Si bien es valioso, hay ocasiones en que debe permitir estos valores en una solicitud. Un ejemplo común es permitir el ingreso de texto enriquecido en un formulario. En estos casos, desafortunadamente, la validación de solicitudes se desactiva con demasiada frecuencia en todo el sitio. Una mejor solución desactiva esta validación solo cuando sea necesario. En versiones anteriores de ASP.NET, agregando validateRequest = "false" al Página La directiva en formularios web desactivaría la validación de una página. En ASP.NET MVC, agregando el [ValidateInput (falso)] El atributo a una acción del controlador desactiva la validación de esa acción, mientras que agrega el [AllowHtml] atributo desactiva la validación de un campo.

ASP.NET 4.0 cambió la validación de la solicitud de varias maneras. Esta y las versiones posteriores del marco hacen la validación al principio de la solicitud HTTP. La validación también se aplica a todas las solicitudes ASP.NET y no solo .aspx solicitudes de página. Esto incluye módulos HTTP personalizados también. Las páginas que se basan en el comportamiento original pueden volver al método anterior configurando requestValidationMode atributo en el web.config archivo a la versión 2.0.

 

Aún mejor, es deshabilitar esto solo para páginas donde sea necesario, usando la sintaxis en el web.configexpediente:

     

ASP.NET 4.5 agregó la capacidad de diferir la validación hasta solicitar los datos. Configurando el requestValidationMode atribuye en tu web.config archivo a la versión 4.5 Activa este nuevo comportamiento..

 

ASP.NET 4.5 también agregó el HttpRequest.Unvalidated propiedad. El uso de esta propiedad permite un acceso más fácil al valor de formulario no validado donde sea necesario. Al combinar la validación diferida y la No validado propiedad, puede acceder a los valores no validados cuando sea necesario, pero proteger otras entradas de formulario.

Codificación HTML

Antes de mostrar datos externos en una página web, su HTML debe estar codificado para que no sea procesado por el navegador. Como ejemplo, tome una página ASP.NET escrita para que se pueda pasar un mensaje para su visualización, como una actualización de estado. Una aplicación podría usar esta página para mostrar al usuario que su cuenta se había creado sin errores. La URL de esta página normalmente sería similar a http: // appname / placeorder / Account + Created. La página resultante muestra el mensaje al usuario con un campo, como por ejemplo:

<%= Html.Label("Message", Model.message) %> 

... y se muestra como:

Si cambiamos la URL llamamos a http: / appname / placeorder /, ahora tenemos algo diferente.

El script podría ser cualquier cosa, por supuesto, y no solo el inofensivo cuadro de alerta que aparece aquí. La validación de la solicitud detectará los ejemplos anteriores y devolverá una excepción antes de la visualización. Sin embargo, si se desactiva, la codificación de la salida evita el ataque.

ASP.NET facilita la codificación de datos para evitar ataques. Las primeras versiones de MVC que usaban la sintaxis de Webform a menudo contenían códigos como este que no codificaban HTML.

<%= status >

Tuvo que codificar manualmente la salida para que cualquier HTML se convirtiera en un formato de visualización. Entonces el < personaje se convierte en la cadena <. los Html.Encode La función proporciona esta conversión. La forma más segura de código se convierte así en:

<%= Html.Encode(status) >

ASP.NET MVC más tarde introdujo una sintaxis para hacer esto en un solo paso reemplazando <= con <: por lo que el código se puede acortar a:

<%: status >

Usando el motor de vista Razor, todos los resultados están codificados en HTML a menos que use un método específicamente para no codificarlo. En Razor, el código equivalente al anterior se convierte en:

@estado

Razor maneja automáticamente la codificación HTML de cualquier cadena estado contiene. En el caso de que necesite representar los datos en bruto, puede utilizar el HTML.Raw () método. Para mostrar el resultado sin codificación, podemos utilizar:

@ Html.Raw (estado)

En este ejemplo, el código anterior haría que nuestra aplicación sea vulnerable. otra vez. Por lo tanto, hay algunas circunstancias en las que no debe codificar la salida. Si deshabilita esta función en un campo, debe tener mucho cuidado para asegurarse de que los datos estén limpios antes de la visualización. Afortunadamente, hay una biblioteca que ayuda con esto, al mismo tiempo que hace más para proteger su aplicación de los scripts entre sitios..

Biblioteca AntiXSS

Si está escribiendo una aplicación ASP.NET, debe usar la biblioteca AntiXSS para ASP.NET. Desde el sitio web del proyecto, "AntiXSS proporciona una gran cantidad de funciones de codificación para las aportaciones de los usuarios, incluidos HTML, atributos HTML, XML, CSS y JavaScript".

La biblioteca contiene métodos enfocados a sanear datos externos basados ​​en el uso previsto de esos datos. Estos métodos utilizan el enfoque basado en lista blanca preferido. Esto significa que los datos codificados, destinados a un atributo HTML, se pueden limpiar para que contengan solo datos válidos para un atributo HTML. El tradicional ASP.NET HtmlEncode los métodos utilizan el enfoque de lista negra que solo codifica ciertos caracteres potencialmente peligrosos.

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

 

Si su aplicación hace una visualización significativa de datos externos, entonces el uso de AntiXSS hará mucho para proteger su aplicación de los scripts entre sitios. Si usa ASP.NET 4.5, entonces cambiar su aplicación para usar los nuevos métodos AntiXSS para la codificación predeterminada proporciona aún más protección para su aplicación web.

En resumen

La prevención de secuencias de comandos entre sitios es más difícil de lo que parece inicialmente. OWASP enumera más de 80 vectores que pueden ser dirigidos usando ataques de scripts entre sitios. Esa organización también enumera estas vulnerabilidades como terceras en su lista de las diez principales vulnerabilidades web de 2013.

Si no se asegura de que todos los datos externos traídos a su aplicación se escapen correctamente o no valida la entrada antes de colocarla en una página de salida, deja su aplicación web vulnerable a los scripts de sitios. En ASP.NET, esto se puede hacer por:

  1. Validación de todas las entradas externas a su aplicación antes de mostrarlas en una página web.
  2. Use la Validación de la solicitud en cualquier lugar donde su aplicación no tenga que desactivarla específicamente, como un formulario que permita una entrada HTML enriquecida. Si debe permitir información no validada, deje la validación en cualquier otro lugar de su aplicación.
  3. Codifique HTML antes de mostrar datos externos en una página web
  4. Use los métodos basados ​​en AntiXSS incluidos en ASP.NET 4.5 y use la biblioteca AntiXSS para versiones anteriores de ASP.NET.