Express.js
XSS y salida segura
Explica cómo el backend participa en la prevención de XSS mediante encoding, Content-Type correcto, validación, CSP y contratos de salida seguros.
- Última actualización
- Actualizada
- Nivel
- Aplicación
Express.js
Explica cómo el backend participa en la prevención de XSS mediante encoding, Content-Type correcto, validación, CSP y contratos de salida seguros.
XSS ocurre cuando datos no confiables terminan ejecutándose como código dentro de un navegador. Una API JSON puede participar en el problema aunque nunca genere HTML directamente.
Cross-Site Scripting no es “guardar una etiqueta <script>”. Es romper la frontera entre datos y código en algún contexto de salida:
input no confiable
→ almacenamiento o reflexión
→ inserción en HTML, atributo, URL o JavaScript
→ ejecución en el origen confiableLa mitigación principal depende del contexto donde se renderiza. Una cadena segura para texto HTML no es necesariamente segura dentro de una URL, CSS o bloque JavaScript.
El payload se almacena y afecta a otros usuarios:
comentario malicioso
→ PostgreSQL
→ panel administrativo
→ script ejecutadoLa aplicación refleja inmediatamente input en una página o error HTML.
El frontend construye un sink peligroso usando datos de URL, API o storage sin pasar necesariamente por HTML generado por el servidor.
La API puede guardar:
{ "displayName": "<img src=x onerror=alert(1)>" }JSON no ejecuta ese valor. El problema aparece cuando un consumidor lo inserta con innerHTML, dangerouslySetInnerHTML o una librería vulnerable.
El backend debe:
Content-Type correctoFrameworks como React escapan texto interpolado.
<p>{comment.body}</p>Necesita sanitización con una librería mantenida y una allowlist estricta.
Valida protocolos y destinos. javascript: puede ser peligroso aunque la cadena esté escapada como texto.
Evítalo. Serializar dentro de <script> requiere escaping específico.
Atributos de evento y URLs tienen reglas distintas a atributos de texto.
Sanitizar HTML significa eliminar nodos, atributos y protocolos no permitidos:
permitir: p, strong, em, ul, li, a[href https]
bloquear: script, iframe, onerror, javascript:No escribas un sanitizer con regex. El parser HTML y los contextos son demasiado complejos.
Content Security Policy limita fuentes de scripts y otros recursos:
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-...'CSP es defensa adicional. No sustituye encoding ni sanitización. Una política con 'unsafe-inline' o orígenes amplios puede perder gran parte de su valor.
Reduce robo directo de session ID mediante JavaScript, pero un XSS todavía puede:
HttpOnly reduce impacto; no elimina XSS.
Supón que DomiSys permite notas de pedido con Markdown:
https: y mailto: si el producto lo necesita.Si el producto realmente necesita rich text HTML, sanitiza en una capa definida y conserva la política versionada.
Sanitizar al guardar reduce riesgo de consumidores olvidadizos, pero dificulta cambiar la política y puede destruir el original. Sanitizar al mostrar conserva datos, pero cada consumidor debe hacerlo correctamente. Puede combinarse almacenamiento original restringido con representación sanitizada.
Puede contener scripts, referencias externas y eventos. No lo trates como una imagen pasiva sin sanitización o aislamiento.
Puede permitir HTML, links peligrosos o imágenes externas. Configura el renderer.
No devuelvas input completo dentro de páginas HTML de error.
Sirve contenido no confiable como attachment y con media type correcto cuando no debe renderizarse inline.
dangerouslySetInnerHTML sin política.Incluye payloads para:
javascript:Usa pruebas de navegador y herramientas de seguridad; una prueba de JSON aislada no reproduce el sink final.
Bloquear todo HTML simplifica seguridad, pero limita edición enriquecida. Permitir rich text mejora producto, pero exige sanitizer, CSP, aislamiento y pruebas continuas.
Security headers y Helmet añade políticas del navegador que reducen superficies específicas.