Cabeceras de seguridad HTTP que importan: CSP, HSTS, X-Content-Type-Options, X-Frame-Options y Referrer-Policy explicados
Por qué las cabeceras de respuesta HTTP importan para la seguridad
Cada respuesta HTTP lleva cabeceras — líneas de metadatos enviadas antes del cuerpo que controlan cómo el navegador maneja el contenido. La mayoría de las cabeceras son mundanas (Content-Type, Cache-Control), pero un conjunto específico de cabeceras de seguridad instruye al navegador para aplicar restricciones que bloquean categorías enteras de ataques. No son medidas de endurecimiento teóricas; son defensas prácticas contra clases de ataques que aparecen repetidamente en el Top 10 de OWASP y las bases de datos CVE. Configurarlas no cuesta nada en rendimiento — añaden aproximadamente 200–400 bytes a cada respuesta — y herramientas como securityheaders.com asignan una calificación a cualquier URL pública para que puedas ver inmediatamente qué cabeceras faltan.
La clave es que las cabeceras de seguridad son aplicadas por el navegador, no por el servidor. El servidor anuncia una política; el navegador la hace cumplir. Esto significa que una mala configuración de cabeceras en un sitio de alto tráfico afecta simultáneamente al navegador de cada visitante. A la inversa, agregar las cabeceras correctas corrige años de riesgo acumulado en una sola implementación. Las cinco cabeceras cubiertas aquí — CSP, HSTS, X-Content-Type-Options, X-Frame-Options y Referrer-Policy — cada una apunta a un comportamiento diferente del navegador que los atacantes pueden explotar.
Content-Security-Policy: el cortafuegos contra XSS
El Cross-Site Scripting (XSS) es la vulnerabilidad web más común en el Top 10 de OWASP. Un atacante que puede inyectar una etiqueta <script> en tu HTML puede robar cookies de sesión, redirigir usuarios o exfiltrar datos de formularios. Content-Security-Policy (CSP) es una cabecera basada en lista blanca que le dice al navegador qué fuentes son de confianza para scripts, estilos, imágenes, fuentes y otros tipos de recursos. La directiva Content-Security-Policy: default-src 'self' permite recursos solo del mismo origen, bloqueando todos los scripts externos y los bloques <script> en línea. Una directiva script-src anula el valor predeterminado específicamente para JavaScript.
La mayor trampa de CSP es la palabra clave unsafe-inline. Agregar script-src 'unsafe-inline' vuelve a habilitar los scripts en línea y derrota completamente la protección XSS de CSP, pero es el recurso más buscado cuando un sitio se rompe después de habilitar CSP. La alternativa correcta son los nonces: cada carga de página genera un valor criptográficamente aleatorio, incluido como script-src 'nonce-r4nd0m' en la cabecera y como nonce="r4nd0m" en cada etiqueta <script> legítima. Un script inyectado sin el nonce coincidente es bloqueado incluso si aparece en línea. Para equipos que aún no están listos para una política estricta, Content-Security-Policy-Report-Only entrega informes de violaciones a un endpoint colector sin bloquear nada — una forma segura de medir el impacto de una política antes de aplicarla.
HTTP Strict Transport Security: prevenir ataques de degradación HTTPS
El SSL stripping es un ataque de degradación demostrado públicamente en Black Hat 2009. Un atacante activo en el camino intercepta la solicitud HTTP inicial del usuario (antes de cualquier redirección a HTTPS) y la proxy como HTTP simple al origen, mientras sirve la conexión cifrada de vuelta al usuario. El usuario ve un candado en algunos navegadores, pero la conexión entre el atacante y el servidor es la no cifrada — las credenciales y las cookies de sesión son visibles en texto plano. HTTP Strict Transport Security (HSTS) cierra esta ventana instruyendo a los navegadores a rechazar completamente las conexiones HTTP para un dominio, por un período definido por la directiva max-age en segundos.
Una cabecera HSTS fuerte típica es Strict-Transport-Security: max-age=31536000; includeSubDomains; preload. El max-age de 31536000 segundos es un año — el mínimo requerido para la inclusión en la lista de precarga HSTS. includeSubDomains extiende la política a cada subdominio. preload señala la intención de ser incluido en la lista de precarga enviada por el navegador en hstspreload.org; una vez en esa lista, los navegadores rechazarán las conexiones HTTP incluso antes de haber visitado el sitio y recibido la cabecera. La restricción crítica: HSTS debe ser entregado sobre una respuesta HTTPS válida. Una cabecera enviada por HTTP es ignorada. Prueba antes de implementar includeSubDomains — si algún subdominio carece de un certificado TLS válido, los usuarios quedarán bloqueados durante todo el período max-age.
X-Content-Type-Options y X-Frame-Options: dos mejoras de seguridad de valor único
El MIME sniffing es un comportamiento heredado donde algunos navegadores inspeccionan los primeros bytes de una respuesta para adivinar su tipo de contenido, anulando la cabecera Content-Type. Internet Explorer era el sniffer de MIME más agresivo; ejecutaría un .jpg como HTML si los primeros bytes parecían marcado. Un atacante que puede subir contenido a tu sitio (una imagen, un archivo de log) puede elaborar una carga útil que se ejecuta como script cuando el navegador la huele. X-Content-Type-Options: nosniff instruye a todos los navegadores modernos a confiar en el Content-Type declarado y omitir el sniffing por completo. Tiene exactamente un valor válido — nosniff — y no hay razón para no configurarlo en cada respuesta.
El clickjacking incrusta tu sitio dentro de un <iframe> en una página controlada por el atacante, luego superpone botones transparentes para que los usuarios hagan clic sin querer en elementos de la UI de tu sitio. X-Frame-Options: DENY evita que tu página sea enmarcada por nadie; X-Frame-Options: SAMEORIGIN solo permite el enmarcado por páginas del mismo origen. La variante ALLOW-FROM uri está obsoleta y no es compatible con los navegadores actuales. El equivalente moderno es la directiva CSP frame-ancestors (frame-ancestors 'none' mapea a DENY, frame-ancestors 'self' mapea a SAMEORIGIN), que además admite múltiples orígenes permitidos. Dado que no todos los navegadores verifican frame-ancestors en todos los contextos, configurar tanto X-Frame-Options como una directiva CSP frame-ancestors proporciona defensa en profundidad.
Referrer-Policy: controlar la fuga de información a través de la cabecera Referer
La cabecera HTTP Referer (escrita con una sola 'r' debido a un error tipográfico histórico en el RFC) envía la URL completa de la página desde la que navegó el usuario a cada recurso externo que esa página carga — imágenes, scripts, hojas de estilo y los destinos de los clics en enlaces. Si un usuario conectado visita /account/reset?token=eyJ... y esa página carga un script de análisis de terceros, la solicitud del script lleva la URL completa incluyendo el token de restablecimiento en la cabecera Referer. La fuga de tokens a través del referrer es una clase de vulnerabilidad bien documentada; GitHub parcheó una exposición de tokens basada en referrer tan recientemente como 2020.
La cabecera Referrer-Policy reemplaza el mecanismo Meta referrer anterior y los workarounds de supresión de la cabecera Referer. La política strict-origin-when-cross-origin es el valor predeterminado recomendado: envía la URL completa para solicitudes del mismo origen (útil para análisis interno), pero solo el origen básico (https://example.com) para solicitudes de origen cruzado, y nada al navegar de HTTPS a HTTP. no-referrer no envía nada, maximizando la privacidad pero rompiendo cualquier análisis que dependa del referrer. unsafe-url siempre envía la URL completa incluyendo ruta y cadena de consulta — el valor predeterminado del navegador antes de 2020 y la fuente de la mayoría de las fugas históricas de referrer. Chrome, Firefox y Safari adoptaron strict-origin-when-cross-origin como predeterminado en 2020–2021 cuando no hay cabecera de política presente, pero configurarlo explícitamente garantiza un comportamiento consistente en todas las versiones del navegador.
Una línea de base de cabeceras de seguridad práctica para cualquier sitio
Para un sitio estático o una aplicación web simple, cuatro cabeceras cubren los vectores de ataque más comunes con una complejidad de configuración mínima: X-Content-Type-Options: nosniff (siempre, una línea); X-Frame-Options: SAMEORIGIN (a menos que tu sitio necesite ser incrustado legítimamente); Referrer-Policy: strict-origin-when-cross-origin; y Strict-Transport-Security: max-age=31536000; includeSubDomains (una vez que hayas confirmado que cada subdominio es HTTPS). CSP requiere más planificación — empieza con Content-Security-Policy-Report-Only y un endpoint de reporte, recopila violaciones durante unos días, luego escribe una política que solo permita lo que realmente usas.
La ubicación de configuración de cabeceras depende de tu stack: Nginx usa directivas add_header en el bloque del servidor; Apache usa Header always set en httpd.conf o .htaccess; Vercel, Netlify y Cloudflare Pages cada uno tiene un archivo de configuración de cabeceras o configuración en el panel de control. La mayoría de los CDN permiten la inyección de cabeceras en el borde, lo cual es preferible a las cabeceras a nivel de aplicación porque el CDN las entrega incluso para respuestas en caché. La herramienta HTTP Headers Checker de TeaFun obtiene cualquier URL pública y muestra qué cabeceras de seguridad están presentes, sus valores y una explicación de referencia rápida de lo que hace cada una — úsala para auditar un sitio antes y después de implementar cambios en las cabeceras.