Los ataques de secuencias de comandos entre sitios ( XSS ) son un tipo de vulnerabilidad de seguridad que se puede encontrar en algunas aplicaciones web . Los ataques XSS permiten a los atacantes inyectar secuencias de comandos del lado del cliente en páginas web vistas por otros usuarios. Los atacantes pueden utilizar una vulnerabilidad de secuencias de comandos entre sitios para eludir los controles de acceso , como la política del mismo origen . Durante la segunda mitad de 2007, XSSed documentó 11.253 vulnerabilidades entre sitios específicas de sitios, en comparación con las 2.134 vulnerabilidades "tradicionales" documentadas por Symantec . [1] Los efectos de XSS varían en rango desde pequeñas molestias hasta un riesgo de seguridad significativo, dependiendo de la sensibilidad de los datos manejados por el sitio vulnerable y la naturaleza de cualquier mitigación de seguridad implementada por la red del propietario del sitio .
OWASP considera que el término cross-site scripting es un nombre inapropiado . Inicialmente era un ataque que se utilizaba para violar datos entre sitios, pero gradualmente comenzó a incluir otras formas de ataques de inyección de datos. [2]
La seguridad en la web depende de una variedad de mecanismos, incluido un concepto subyacente de confianza conocido como política del mismo origen . Esta establece que si se concede permiso al contenido de un sitio (como https://mybank.example1.com ) para acceder a recursos (como cookies, etc.) en un navegador web, entonces el contenido de cualquier URL con el mismo (1) esquema de URI (por ejemplo, ftp, http o https), (2) nombre de host y (3) número de puerto compartirá estos permisos. El contenido de las URL donde cualquiera de estos tres atributos sea diferente deberá recibir permisos por separado. [3]
Los ataques de secuencias de comandos entre sitios utilizan vulnerabilidades conocidas en las aplicaciones basadas en la Web , sus servidores o los sistemas de complementos de los que dependen. Al explotar una de ellas, los atacantes incorporan contenido malicioso al contenido que se entrega desde el sitio afectado. Cuando el contenido combinado resultante llega al navegador web del lado del cliente, todo ha sido entregado desde la fuente de confianza y, por lo tanto, funciona con los permisos otorgados a ese sistema. Al encontrar formas de inyectar secuencias de comandos maliciosas en las páginas web, un atacante puede obtener privilegios de acceso elevados al contenido confidencial de la página, a las cookies de sesión y a una variedad de otra información mantenida por el navegador en nombre del usuario. Los ataques de secuencias de comandos entre sitios son un caso de inyección de código .
Los ingenieros de seguridad de Microsoft introdujeron el término "cross-site scripting" en enero de 2000. [4] La expresión "cross-site scripting" se refería originalmente al acto de cargar la aplicación web de terceros atacada desde un sitio de ataque no relacionado, de manera que se ejecuta un fragmento de JavaScript preparado por el atacante en el contexto de seguridad del dominio objetivo (aprovechando una vulnerabilidad XSS reflejada o no persistente ). La definición se amplió gradualmente para abarcar otros modos de inyección de código, incluidos vectores persistentes y no JavaScript (incluidos ActiveX , Java , VBScript , Flash o incluso scripts HTML ), lo que provocó cierta confusión entre los recién llegados al campo de la seguridad de la información . [5]
Las vulnerabilidades XSS han sido reportadas y explotadas desde la década de 1990. Entre los sitios más destacados afectados en el pasado se incluyen los sitios de redes sociales Twitter [6] y Facebook . [7] Desde entonces, las fallas de secuencias de comandos entre sitios han superado los desbordamientos de búfer para convertirse en la vulnerabilidad de seguridad informada públicamente más común, [8] y algunos investigadores en 2007 estimaron que hasta un 68% de los sitios web probablemente estén expuestos a ataques XSS. [9]
No existe una clasificación estandarizada y única de los fallos de secuencias de comandos entre sitios, pero la mayoría de los expertos distinguen al menos dos tipos principales de fallos XSS: no persistentes y persistentes . Algunas fuentes dividen a su vez estos dos grupos en tradicionales (causados por fallos de código del lado del servidor) y basados en DOM (en el código del lado del cliente).
La vulnerabilidad de secuencias de comandos entre sitios no persistente (o reflejada ) es, con diferencia, el tipo más básico de vulnerabilidad web. [10] Estos agujeros aparecen cuando los datos proporcionados por un cliente web, [11] más comúnmente en parámetros de consulta HTTP (por ejemplo, envío de formulario HTML), son utilizados inmediatamente por secuencias de comandos del lado del servidor para analizar y mostrar una página de resultados para y para ese usuario, sin desinfectar adecuadamente el contenido. [12]
Debido a que los documentos HTML tienen una estructura plana y serial que mezcla declaraciones de control, formato y el contenido real, cualquier dato no validado proporcionado por el usuario incluido en la página resultante sin la codificación HTML adecuada puede dar lugar a una inyección de marcado. [10] [12] Un ejemplo clásico de un vector potencial es un motor de búsqueda de un sitio: si uno busca una cadena, la cadena de búsqueda normalmente se volverá a mostrar textualmente en la página de resultados para indicar lo que se buscó. Si esta respuesta no escapa o rechaza correctamente los caracteres de control HTML, se producirá una falla de secuencias de comandos entre sitios. [13]
Un ataque reflejado se suele enviar por correo electrónico o a un sitio web neutral. El cebo es una URL de apariencia inocente que apunta a un sitio confiable pero que contiene el vector XSS. Si el sitio confiable es vulnerable al vector, al hacer clic en el enlace, el navegador de la víctima puede ejecutar el script inyectado.
La vulnerabilidad XSS persistente (o almacenada ) es una variante más devastadora de un fallo de secuencias de comandos entre sitios: se produce cuando los datos proporcionados por el atacante son guardados por el servidor y luego se muestran de forma permanente en páginas "normales" que se devuelven a otros usuarios durante la navegación habitual, sin el escape HTML adecuado. Un ejemplo clásico de esto es el de los foros de mensajes en línea, donde se permite a los usuarios publicar mensajes con formato HTML para que otros usuarios los lean. [12]
Por ejemplo, supongamos que existe un sitio web de citas en el que los miembros escanean los perfiles de otros miembros para ver si parecen interesantes. Por razones de privacidad, este sitio oculta el nombre real y el correo electrónico de todos los usuarios. Estos se mantienen en secreto en el servidor. La única vez que el nombre real y el correo electrónico de un miembro aparecen en el navegador es cuando el miembro ha iniciado sesión y no puede ver los de nadie más.
Supongamos que Mallory, una atacante, se une al sitio y quiere averiguar los nombres reales de las personas que ve en el sitio. Para ello, escribe un script diseñado para ejecutarse desde los navegadores de otros usuarios cuando visitan su perfil . El script envía entonces un mensaje rápido a su propio servidor, que recopila esta información.
Para ello, a la pregunta "Describe tu primera cita ideal", Mallory da una respuesta corta (para parecer normal), pero el texto al final de su respuesta es su script para robar nombres y correos electrónicos. Si el script está encerrado dentro de un <script>
elemento, no se mostrará en la pantalla. Supongamos que Bob, un miembro del sitio de citas, llega al perfil de Mallory, que tiene su respuesta a la pregunta de la primera cita. Su script es ejecutado automáticamente por el navegador y roba una copia del nombre real y el correo electrónico de Bob directamente de su propia máquina.
Las vulnerabilidades XSS persistentes pueden ser más significativas que otros tipos porque el código malicioso del atacante se ejecuta automáticamente, sin necesidad de atacar a las víctimas individualmente o atraerlas a un sitio web de terceros. En particular, en el caso de los sitios de redes sociales, el código estaría diseñado para autopropagarse entre cuentas, creando un tipo de gusano del lado del cliente . [14]
Los métodos de inyección pueden variar mucho; en algunos casos, el atacante puede no necesitar ni siquiera interactuar directamente con la funcionalidad web para explotar un agujero de seguridad de este tipo. Cualquier dato recibido por la aplicación web (por correo electrónico, registros del sistema, mensajería instantánea, etc.) que pueda ser controlado por un atacante podría convertirse en un vector de inyección.
Las vulnerabilidades XSS se encontraron originalmente en aplicaciones que realizaban todo el procesamiento de datos en el lado del servidor. La entrada del usuario (incluido un vector XSS) se enviaba al servidor y luego se enviaba de vuelta al usuario como una página web. La necesidad de una mejor experiencia del usuario dio lugar a la popularidad de las aplicaciones que tenían la mayor parte de la lógica de presentación (tal vez escrita en JavaScript ) funcionando en el lado del cliente que extraía datos, a pedido, del servidor mediante AJAX .
Como el código JavaScript también procesaba la entrada del usuario y la presentaba en el contenido de la página web, comenzó a aparecer una nueva subclase de ataques XSS reflejados, que se denominaron ataques de secuencias de comandos entre sitios basados en DOM . En un ataque XSS basado en DOM, los datos maliciosos no tocan el servidor web, sino que se reflejan en el código JavaScript, completamente en el lado del cliente. [15]
Un ejemplo de una vulnerabilidad XSS basada en DOM es el error encontrado en 2011 en varios complementos de jQuery . [16] Las estrategias de prevención para ataques XSS basados en DOM incluyen medidas muy similares a las estrategias de prevención XSS tradicionales pero implementadas en código JavaScript y contenidas en páginas web (es decir, validación de entrada y escape). [17] Algunos marcos de JavaScript tienen contramedidas integradas contra este y otros tipos de ataques, por ejemplo AngularJS . [18]
Self-XSS es una forma de vulnerabilidad XSS que se basa en la ingeniería social para engañar a la víctima y hacer que ejecute código JavaScript malicioso en su navegador. Aunque técnicamente no es una verdadera vulnerabilidad XSS debido a que se basa en la ingeniería social para que un usuario ejecute código en lugar de una falla en el sitio web afectado que permita que un atacante lo haga, aún plantea los mismos riesgos que una vulnerabilidad XSS normal si se ejecuta correctamente. [19]
El XSS mutado ocurre cuando el atacante inyecta algo que parece seguro pero que el navegador reescribe y modifica mientras analiza el código. Esto hace que sea extremadamente difícil detectarlo o sanearlo dentro de la lógica de la aplicación del sitio web. Un ejemplo es reequilibrar las comillas sin cerrar o incluso agregar comillas a los parámetros sin comillas en los parámetros de la familia de fuentes CSS.
Hay varios esquemas de escape que se pueden usar dependiendo de dónde se debe colocar la cadena no confiable dentro de un documento HTML, incluida la codificación de entidad HTML, el escape de JavaScript, el escape de CSS y la codificación de URL (o porcentaje) . [20] La mayoría de las aplicaciones web que no necesitan aceptar datos enriquecidos pueden usar el escape para eliminar en gran medida el riesgo de ataques XSS de una manera bastante sencilla.
Realizar la codificación de entidades HTML solo en los cinco caracteres XML significativos no siempre es suficiente para prevenir muchas formas de ataques XSS; las bibliotecas de codificación de seguridad suelen ser más fáciles de usar. [20]
Algunos sistemas de plantillas web entienden la estructura del HTML que producen y seleccionan automáticamente un codificador apropiado. [21] [22] [23]
Muchos operadores de aplicaciones web específicas (por ejemplo, foros y correo web) permiten a los usuarios utilizar un subconjunto limitado de marcado HTML. Al aceptar una entrada HTML de los usuarios (por ejemplo, <b>very</b> large
), la codificación de salida (como <b>very</b> large
) no será suficiente, ya que la entrada del usuario debe ser procesada como HTML por el navegador (para que se muestre como " muy grande", en lugar de "<b>muy</b> grande"). Detener un ataque XSS al aceptar una entrada HTML de los usuarios es mucho más complejo en esta situación. La entrada HTML no confiable debe ejecutarse a través de un motor de desinfección HTML para garantizar que no contenga código XSS.
Muchas validaciones se basan en el análisis (inclusión en la lista negra) de etiquetas HTML específicas "en riesgo", como la etiqueta iframe , la etiqueta link y la etiqueta script.
Este enfoque presenta varios problemas; por ejemplo, a veces se pueden omitir etiquetas aparentemente inofensivas que, cuando se utilizan correctamente, pueden generar un XSS.
Otro método popular es quitarle al usuario la entrada de "y"; sin embargo, esto también se puede omitir, ya que la carga útil se puede ocultar con ofuscación .
Además del filtrado de contenido, también se utilizan comúnmente otros métodos imperfectos para mitigar los ataques de secuencias de comandos entre sitios. Un ejemplo es el uso de controles de seguridad adicionales al manejar la autenticación de usuarios basada en cookies . Muchas aplicaciones web dependen de las cookies de sesión para la autenticación entre solicitudes HTTP individuales y, dado que los scripts del lado del cliente generalmente tienen acceso a estas cookies, los exploits XSS simples pueden robar estas cookies. [24] Para mitigar esta amenaza en particular (aunque no el problema XSS en general), muchas aplicaciones web vinculan las cookies de sesión a la dirección IP del usuario que inició sesión originalmente y luego solo permiten que esa IP use esa cookie. [25] Esto es efectivo en la mayoría de las situaciones (si un atacante solo busca la cookie), pero obviamente falla en situaciones en las que un atacante está detrás de la misma dirección IP NAT o proxy web que la víctima, o la víctima está cambiando su IP móvil . [25]
Otra mitigación presente en Internet Explorer (desde la versión 6), Firefox (desde la versión 2.0.0.5), Safari (desde la versión 4), Opera (desde la versión 9.5) y Google Chrome , es un indicador HttpOnly que permite a un servidor web establecer una cookie que no está disponible para los scripts del lado del cliente. Si bien es beneficiosa, la característica no puede evitar por completo el robo de cookies ni prevenir ataques dentro del navegador. [26]
Si bien los desarrolladores de Web 2.0 y Ajax requieren el uso de JavaScript, [27] algunas aplicaciones web están escritas para permitir su funcionamiento sin la necesidad de ningún script del lado del cliente. [28] Esto permite a los usuarios, si así lo desean, desactivar los scripts en sus navegadores antes de usar la aplicación. De esta manera, incluso scripts del lado del cliente potencialmente maliciosos podrían insertarse sin escape en una página y los usuarios no serían susceptibles a ataques XSS.
Algunos navegadores o complementos de navegador pueden configurarse para desactivar los scripts del lado del cliente por dominio. Este enfoque tiene un valor limitado si se permite la creación de scripts de forma predeterminada, ya que bloquea los sitios maliciosos solo después de que el usuario sabe que son malos, lo que es demasiado tarde. La funcionalidad que bloquea todos los scripts y las inclusiones externas de forma predeterminada y luego permite al usuario habilitarlos por dominio es más efectiva. Esto ha sido posible durante mucho tiempo en Internet Explorer (desde la versión 4) configurando sus llamadas "Zonas de seguridad", [29] y en Opera (desde la versión 9) utilizando sus "Preferencias específicas del sitio". [30] Una solución para Firefox y otros navegadores basados en Gecko es el complemento de código abierto NoScript que, además de la capacidad de habilitar scripts por dominio, proporciona cierta protección XSS incluso cuando los scripts están habilitados. [31]
El problema más importante que supone bloquear todos los scripts de todos los sitios web de forma predeterminada es la reducción sustancial de la funcionalidad y la capacidad de respuesta (los scripts del lado del cliente pueden ser mucho más rápidos que los del lado del servidor porque no necesitan conectarse a un servidor remoto y no es necesario volver a cargar la página o el marco ). [32] Otro problema del bloqueo de scripts es que muchos usuarios no lo entienden y no saben cómo proteger adecuadamente sus navegadores. Otro inconveniente es que muchos sitios no funcionan sin scripts del lado del cliente, lo que obliga a los usuarios a desactivar la protección de ese sitio y abre sus sistemas a vulnerabilidades. [33] La extensión NoScript de Firefox permite a los usuarios permitir scripts de forma selectiva de una página determinada y deshabilitar otros en la misma página. Por ejemplo, se podrían permitir los scripts de example.com, mientras que se podrían deshabilitar los scripts de advertisingagency.com que intenten ejecutarse en la misma página. [34]
La política de seguridad de contenido (CSP) permite que los documentos HTML desactiven algunos scripts y dejen otros habilitados. [35] El navegador verifica cada script con una política antes de decidir si ejecutarlo. Mientras la política solo permita scripts confiables y no permita la carga dinámica de código , el navegador no ejecutará programas de autores no confiables independientemente de la estructura del documento HTML.
Las políticas modernas de CSP permiten usar nonces para marcar scripts en el documento HTML como seguros para ejecutarse en lugar de mantener la política completamente separada del contenido de la página. [36] [37] Mientras los nonces confiables solo aparezcan en scripts confiables, el navegador no ejecutará programas de autores no confiables. Algunos grandes proveedores de aplicaciones informan que han implementado con éxito políticas basadas en nonce. [38] [39]
Los tipos confiables [40] modifican las API web para verificar que los valores hayan sido registrados como confiables. Mientras los programas registren únicamente valores confiables, un atacante que controle un valor de cadena de JavaScript no puede provocar XSS. Los tipos confiables están diseñados para que los equipos azules puedan auditarlos .
Otro enfoque de defensa es utilizar herramientas automatizadas que eliminarán el código malicioso XSS en las páginas web, estas herramientas utilizan análisis estáticos y/o métodos de coincidencia de patrones para identificar códigos potencialmente maliciosos y protegerlos utilizando métodos como el escape. [41]
Cuando se configura una cookie con el SameSite=Strict
parámetro , se elimina de todas las solicitudes de origen cruzado. Cuando se configura con SameSite=Lax
, se elimina de todas las solicitudes de origen cruzado que no sean "seguras" (es decir, solicitudes distintas de GET, OPTIONS y TRACE que tienen semántica de solo lectura). [42] La función se implementa en Google Chrome desde la versión 63 y en Firefox desde la versión 60. [43]
16 de enero de 2000, se sugirieron y analizaron los siguientes nombres entre un pequeño grupo de ingenieros de seguridad de Microsoft: [...] Al día siguiente hubo consenso: Cross Site Scripting.