Las biografías de perfil proporcionadas por los usuarios se renderizan sin escapar, y una contiene una etiqueta `<script>`. ¿Cuál es la corrección correcta?
Respuesta breve
El XSS almacenado se corrige codificando los datos para el contexto exacto donde se renderizan (cuerpo HTML, atributo, JavaScript, URL) para que el navegador los trate como texto, con una Content-Security-Policy como segunda capa. Poner la palabra «script» en lista negra se evita trivialmente mediante manejadores de eventos, mayúsculas mezcladas y codificaciones. No puedes obligar a tus usuarios a desactivar JavaScript. Pedir a los usuarios que no introduzcan HTML no es un control aplicable. Codifica en la salida, cada vez que renderizas.
La biografía se almacena y luego se renderiza en una página sin codificarse, así que una etiqueta <script> que contenga se ejecuta en el navegador de cada visitante. Es cross-site scripting almacenado (persistente) — una sola carga inyectada golpea a cada usuario que carga el perfil. La causa raíz es que los datos se interpretan como marcado en el momento del renderizado.
La corrección correcta: codificación de salida según el contexto
El XSS es un problema de renderizado, así que corrígelo donde los datos se encuentran con la página: codifica en la salida, para el contexto específico.
- En contexto de cuerpo HTML, codifica
<,>,&, etc., para que el navegador muestre el texto en lugar de analizar una etiqueta. - En contexto de atributo HTML, JavaScript o URL, la codificación correcta difiere — usar la equivocada sigue dejando un agujero.
Los frameworks modernos escapan automáticamente por defecto; el fallo suele aparecer donde alguien recurre a un escape de HTML en crudo. Añade una Content-Security-Policy como defensa en profundidad para que, aunque se omita una codificación, se bloqueen los scripts en línea y no confiables.
Por qué los distractores son erróneos
- Eliminar la palabra «script» es una lista negra de entrada, evitada trivialmente: una etiqueta
imgcon un manejadoronerror, una etiquetasvgcononload, mayúsculas mezcladas, entidades HTML y decenas de otros vectores no contienen ningún «script» literal. - Decir a los usuarios que desactiven JavaScript es absurdo como control — no manejas los navegadores de tus usuarios, y la aplicación depende de JS de todos modos.
- Pedir a los usuarios que no introduzcan HTML es una solicitud, no una imposición; el atacante simplemente la ignora.
Qué evalúa el entrevistador
Si sabes que el XSS se corrige en la salida, en el contexto correcto, y no filtrando entradas contra una lista de denegación, y si superpones un CSP sin confundirlo con la corrección principal. Los buenos candidatos señalan que la validación de entrada y el saneamiento de HTML de confianza tienen su lugar (en campos de texto enriquecido), pero que la codificación de salida contextual es el control fiable y universal.
Posibles preguntas de seguimiento
- ¿Por qué la codificación de salida depende del contexto — en qué difiere codificar para un atributo HTML frente a una cadena JS?
- ¿Qué aporta una Content-Security-Policy y por qué no sustituye a la codificación?
- ¿Cuándo es apropiado el saneamiento de entrada (p. ej. un sanitizador HTML) en lugar de la codificación?