Inyección - XSS
Cross-Site Scripting, también conocido como XSS, es otro tipo de vulnerabilidad de inyección que conduce a la evaluación de un script controlado por el atacante en el navegador de otro usuario. XSS también puede considerarse una vulnerabilidad de inyección HTML/JavaScript.
El impacto de una vulnerabilidad XSS depende en gran medida del contexto en el que se encuentre. Va desde poder extraer información de la página en la que se ejecuta el script hasta editar el estado de la página para realizar acciones como la víctima en la página.
Veamos los tipos de XSS que se pueden encontrar.
Tipos de XSS
Los XSS pueden dividirse en varios grupos para ayudar a distinguirlos. Se clasifican por la forma en que se entrega la carga útil y dónde está el punto de entrada.
Vector de entrega de la carga útil (almacenada o reflejada)
Hay dos formas en que un atacante puede entregar una carga útil XSS:
- XSS almacenado: a través de datos controlados por el usuario almacenados en, por ejemplo, una base de datos donde los datos se muestran a otros usuarios.
- XSS reflejado: A través de una carga útil proporcionada por el usuario que se pasa a través de la URL/cadena de consulta a la que navega un usuario.
La distinción crítica es que un XSS Reflejado normalmente dependerá de la interacción del usuario y sólo afectará al usuario que abra el enlace con la carga maliciosa. Sin embargo, un XSS Almacenado puede ser ejecutado contra uno o más usuarios simplemente abriendo algunas páginas que renderizan la carga maliciosa.
Ubicación de la carga útil (DOM vs Non-DOM)
La ubicación en la que se inyecta una carga útil determina si se categoriza la vulnerabilidad como una vulnerabilidad "DOM" o no. Esto se refiere a la distinción entre dónde se renderiza la carga útil:
- XSS no-DOM: La carga útil se renderiza dentro de HTML, ya sea dentro de una etiqueta o de un atributo.
- DOM XSS: The payload is rendered inside JavaScript, like a `<script>` tag, or an event handler such as `onclick=""`
XSS - Primitivas de defensa
En esta sección, veremos los principios de las primitivas que subyacen a la defensa contra XSS. Entender los fundamentos de esto es esencial, pero en la práctica, deberías confiar en tu librería de plantillas para el 99% de la protección contra XSS.
Cuando se escriben plantillas que se convierten en marcas o código que se ejecuta en un navegador, la clave para protegerse contra XSS es la *codificación*. Codificar, en este contexto, significa tomar una secuencia de caracteres y cambiarla a un formato que sea procesado de una manera específica por el intérprete.
Pero el tipo de codificación a utilizar depende de la ubicación o el contexto en el que se utilizarán los datos.
- Inside a tag, like `<div>User input here</div>`: **HTML Encoding**
- Inside an attribute, like `<input placeholder="User input here"></input>`: **Attribute Encoding**
- Inside Javascript, like `<script>x = "User input here";</script>`: **JavaScript Encoding**
Algunos frameworks renunciarán a la codificación como su principal medio de defensa y en su lugar utilizarán la sanitización para limpiar un valor de cualquier contenido que pudiera ser peligroso. Este es un proceso mucho más complejo con muchos casos extremos a considerar. No se recomienda implementar sus propias rutinas de desinfección.
Ejemplos
Veamos algunos ejemplos en varios idiomas para ver cómo queda todo en acción.
C# - Inseguro: Razor
Si un objeto `IHtmlContent` lleva como prefijo `@`, el valor se coloca directamente en la plantilla sin ninguna codificación.
<!--- UNSAFE: The htmlSnippet will get interpreted without any escaping --->
@Html.Raw(htmlSnippet)
C# - Seguro: Razor
Por defecto, cualquier `cadena` precedida de `@` se escapa de HTML en las plantillas Razor.
<!--- SAFE: The htmlSnippet will get HTML escaped --->
@htmlSnippet
Java - Seguro: JSP
Cuando se utiliza `c:out`, por defecto es XML escape (Que se puede cambiar con la propiedad `escapeXml`), que protege contra XSS en un contexto HTML, pero no en otros contextos.
<div><c:out value="<%= author %>" /></div>
Java - Seguro: (fnxml)
De forma similar a lo anterior, también puede llamar directamente a `fn:escapeXml`, que escapará XML de la entrada que se le dé. Esto también sólo protegerá en un contexto HTML.
<div>${fn:escapeXml(author)}</div>
Javascript - Inseguro: Angular innerHtml
Al especificar la propiedad `innerHTML`, como su nombre indica, estará expuesto al riesgo de XSS debido a la desactivación de la codificación de salida.
<!--- UNSAFE: The htmlSnippet will get interpreted without any encoding --->
<p [innerHTML]="htmlSnippet"></p>
Javascript - Seguro: Angular interpolado
La interpolación de Angular de texto usando llaves dobles (`{{` y `}}`) escapará HTML de su salida, protegiendo contra XSS.
<!--- SAFE: The htmlSnippet will get encoded and then interpreted --->
<p>{{htmlSnippet}}</p>
Javascript - Inseguro: React dangerousInnerHtml
Al especificar la propiedad `dangerouslySetInnerHTML`, como su nombre indica, estará expuesto al riesgo de XSS debido a la desactivación de la codificación de salida.
<!--- UNSAFE: As the name suggests, the dangerouslySetInnerHTML attribute is dangerous as it does not escape the output --->
<div dangerouslySetInnerHTML={{ __html: htmlSnippet }} />;
Javascript - Seguro: React interpolado
La interpolación de React de texto utilizando llaves (`{` y `}`) escapará HTML de su salida, protegiendo contra XSS.
<!--- SAFE: The htmlSnippet will get encoded and then interpreted --->
<div>{htmlSnippet}</div>
Python - Inseguro: Django
Si se utiliza el filtro `safe` en una plantilla Django, se desactivará el escape automático de la salida, y por lo tanto no protegerá contra XSS.
<!--- UNSAFE: The htmlSnippet will not get HTML encoded --->
<div>{{ htmlSnippet | safe }}</div>
Python - Seguro: Django
La interpolación de texto de Django utilizando llaves dobles (`{{` y `}}`) escapará HTML de su salida, protegiendo contra XSS.
<!--- SAFE: The htmlSnippet will HTML encoded --->
<div>{{ name }}</div>