XSS local defensivo: source, sink y output encoding
Un lab local para entender XSS sin tocar sitios ajenos: de dónde entra el dato, dónde se interpreta como HTML y cómo cortarlo con APIs seguras.
Antes de empezar necesitás
- Un navegador moderno
- Una terminal con Python 3 opcional para servir archivos locales
Al terminar vas a poder
- Distinguir source, sink y contexto
- Ver por qué innerHTML con input no confiable es peligroso
- Aplicar textContent como mitigación simple
- Documentar el bug y el fix sin atacar terceros
XSS no es “pegar un script en una web”. Es un bug de contexto: un dato que debía ser tratado como texto termina siendo interpretado como HTML o JavaScript. En este lab lo ves en local, sin tocar sitios ajenos.
Página vulnerable de juguete
Creá un archivo local xss-demo.html con una idea como esta:
<div id="saludo"></div>
<script>
const params = new URLSearchParams(location.search);
const name = params.get("name") ?? "mundo";
document.querySelector("#saludo").innerHTML = `Hola ${name}`;
</script>
El source es location.search. El sink es innerHTML. El problema es que innerHTML interpreta HTML.
python3 -m http.server 8000Abrí http://localhost:8000/xss-demo.html?name=Valen y después probá un valor con etiquetas HTML. No uses sitios de terceros: esto es tu archivo local.
El fix mínimo
Si querés mostrar texto, usá una API que escriba texto:
<script>
const params = new URLSearchParams(location.search);
const name = params.get("name") ?? "mundo";
document.querySelector("#saludo").textContent = `Hola ${name}`;
</script>
Ahora el navegador no interpreta el contenido como HTML: lo muestra como texto.
Evidencia esperada
Documentá el bug con esta tabla:
source: query string (?name=...)
sink malo: innerHTML
impacto: input no confiable se interpreta como markup
fix: textContent para renderizar texto
Lo que practicás en este lab
Llevátelo a tu repo si querés, pero no es obligatorio: es tu aprendizaje.
- Archivo HTML local vulnerable y versión corregida
- Screenshot o nota mostrando que el payload queda como texto
- Writeup con source, sink, impacto y mitigación
Reto
Armá una mini página local que lea ?name= de la URL. Primero renderizalo mal con innerHTML, después corregilo con textContent. Explicá source, sink y fix.
Resolvelo y escribí dos líneas explicando qué pasó. Con eso lo fijás.