Saltar al contenido principal
riqo.ioHerramientas para grandes ideas

Escaping vs sanitization: contextos HTML y prevención de XSS

Por qué escaping contextual y sanitization resuelven problemas distintos y cómo impedir que entradas no confiables se conviertan en markup activo.

Concepto y contexto

Escaping y sanitization son defensas diferentes: escaping representa datos para que no se interpreten como sintaxis en un contexto de salida, mientras sanitization analiza contenido estructurado y elimina o transforma construcciones no permitidas.

Confundirlas produce filtros incompletos.

Un buen modelo mental separa el concepto abstracto de su representación concreta y del entorno donde se utiliza. Esa separación evita trasladar automáticamente supuestos válidos en un protocolo, biblioteca o formato hacia sistemas que pueden aplicar reglas o garantías diferentes.

Fundamentos y terminología

El escaping correcto depende del contexto porque texto HTML, atributos, URL, CSS y JavaScript tienen gramáticas distintas.

Una representación segura en texto de elemento no es automáticamente segura dentro de un atributo de evento o una cadena JavaScript.

La terminología debe leerse junto con el estándar, versión o contrato que la define, porque palabras parecidas pueden describir propiedades distintas según la capa. Explicitar esas definiciones mejora interoperabilidad, documentación y capacidad para diagnosticar comportamientos inesperados.

Cómo funciona

Los template engines modernos suelen auto-escapar texto interpolado, pero las API de HTML raw pueden saltarse esa protección.

Un sanitizer debe comprender el markup, aplicar allowlist y tratar atributos, esquemas URL y construcciones peligrosas.

En sistemas reales conviene seguir el recorrido de los datos entre capas e identificar qué transformaciones son reversibles, cuáles introducen restricciones y dónde puede perderse información. Así resulta más sencillo razonar sobre responsabilidades entre productores, consumidores, almacenamiento y transporte.

Ejemplo razonado

Mostrar <b>Hola</b> literalmente solo requiere escapar delimitadores HTML; permitir voluntariamente parte del markup exige sanitization estructural.

Una política puede conservar b y em pero eliminar script, event handlers y URL javascript:.

Un ejemplo razonado es reutilizable cuando muestra sus precondiciones e invariantes y no solo el resultado final. Cambiar un supuesto cada vez permite distinguir el comportamiento garantizado por un estándar de las decisiones particulares de una aplicación o implementación.

Errores y conceptos equivocados

Sustituir solo < y > no cubre todos los contextos y las expresiones regulares genéricas no son parsers HTML fiables.

Decodificaciones múltiples, mutaciones DOM y concatenación entre contextos pueden reactivar contenido después de un filtro inicial.

Muchos fallos nacen de supuestos implícitos entre sistemas aparentemente compatibles que usan versiones, reglas de canonicalización o modelos de tipos diferentes. En interoperabilidad y seguridad conviene especificar y probar entradas anómalas en lugar de tratarlas como casos irrelevantes.

Buenas prácticas y criterios de elección

Mantén datos no confiables como texto siempre que sea posible, usa auto-escaping contextual y sanitizers maduras solo cuando aceptar HTML sea un requisito.

Añade Content Security Policy como defensa adicional, no como sustituto de encoding y validación correctos.

Una práctica robusta combina estándares documentados, bibliotecas maduras, contratos explícitos y pruebas con casos límite representativos. La mejor elección no es siempre la más breve o popular: también cuentan portabilidad, legibilidad, rendimiento, seguridad, evolución y coste operativo.

Guías relacionadas

HTML entities, escaping y seguridad del markup

Referencias de caracteres HTML, referencias numéricas, escaping contextual, sanitization y su relación con XSS.

Bit, byte, nibble, enteros fixed-width y complemento a dos

Cómo los ordenadores representan bits e enteros signed y por qué anchura e interpretación cambian el valor observado.