Tecnología

Cabeceras de seguridad HTTP: cuáles configurar en cualquier web y qué hace cada una

Qué hacen HSTS, Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, Referrer-Policy y Permissions-Policy, con valores recomendados y cómo comprobarlos.

Las cabeceras de seguridad HTTP son instrucciones que el servidor envía junto a cada respuesta para que el navegador aplique protecciones adicionales: forzar HTTPS (Strict-Transport-Security), limitar de dónde se pueden cargar scripts y otros recursos (Content-Security-Policy), impedir que el sitio se incruste en otras páginas (X-Frame-Options / frame-ancestors), evitar que el navegador “adivine” tipos de archivo (X-Content-Type-Options), controlar qué información de referencia se envía a otros sitios (Referrer-Policy) y desactivar APIs del navegador que no usas (Permissions-Policy). Se configuran en el servidor o en el proveedor de hosting, no en el HTML, y un sitio estático puede tenerlas todas en minutos.

Este artículo explica qué hace cada una, qué valor usar en una web típica y cómo comprobar que están activas.

Por qué importan en una web “sin nada que robar”

Un blog sin usuarios registrados parece un objetivo poco interesante, pero las cabeceras protegen a tus visitantes: evitan que un script de terceros comprometido inyecte código, que alguien incruste tu web en un marco para engañar con clics (clickjacking) o que una conexión degradada a HTTP permita manipular el contenido. Además son gratuitas en rendimiento y señalan un sitio mantenido con cuidado.

Las seis cabeceras y sus valores recomendados

1. Strict-Transport-Security (HSTS)

Indica al navegador que, durante el tiempo indicado, solo se conecte a tu dominio por HTTPS, aunque el usuario escriba http:// o pulse un enlace antiguo.

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
  • max-age=31536000: un año, en segundos.
  • includeSubDomains: aplica también a los subdominios. Asegúrate de que todos sirven HTTPS antes de activarlo.
  • preload: permite incluir el dominio en la lista de precarga integrada en los navegadores, de modo que ni la primera visita use HTTP. Solo añade preload si de verdad vas a enviar el dominio a la lista; es difícil de revertir.

Empieza con un max-age corto (por ejemplo, 300) para comprobar que nada se rompe y súbelo después.

2. Content-Security-Policy (CSP)

Es la más potente y la más delicada: define de qué orígenes puede cargar el navegador scripts, estilos, imágenes, fuentes, conexiones e iframes. Un script inyectado desde un origen no autorizado simplemente no se ejecuta.

Un punto de partida para un sitio estático sin terceros:

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src 'none'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; upgrade-insecure-requests

Notas prácticas:

  • 'self' es tu propio origen. Cada servicio externo (analítica, publicidad, fuentes, vídeos) hay que añadirlo explícitamente a la directiva que corresponda.
  • Evita 'unsafe-inline' en script-src: anula gran parte de la protección. Si necesitas scripts inline, usa nonces o hashes. En style-src se tolera con más frecuencia porque muchos resaltadores de código y componentes generan estilos inline, aunque lo ideal es eliminarlo también.
  • frame-ancestors 'none' sustituye a X-Frame-Options en navegadores modernos.
  • Prueba primero con Content-Security-Policy-Report-Only, que informa de las violaciones sin bloquear nada, y mira la consola del navegador.

3. X-Content-Type-Options

X-Content-Type-Options: nosniff

Impide que el navegador interprete un archivo como un tipo distinto al declarado en Content-Type (por ejemplo, ejecutar como script algo servido como texto). Siempre, sin excepciones.

4. X-Frame-Options

X-Frame-Options: DENY

Prohíbe que tu página se cargue dentro de un <iframe> de otro sitio (protección contra clickjacking). SAMEORIGIN permite incrustarla solo desde tu propio dominio. Hoy la CSP con frame-ancestors cubre lo mismo con más precisión; mantén ambas para navegadores antiguos.

5. Referrer-Policy

Referrer-Policy: strict-origin-when-cross-origin

Controla qué parte de la URL de origen se envía en la cabecera Referer al navegar a otro sitio. Con este valor, a otros dominios solo se envía el origen (https://blog.aimran.es) y nunca la ruta completa, y nada si se pasa de HTTPS a HTTP. Es el valor por defecto de los navegadores modernos, pero declararlo evita depender de ello.

6. Permissions-Policy

Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=()

Desactiva APIs del navegador que tu web no utiliza, también para cualquier iframe de terceros que incrustes. La lista de funciones disponibles está en MDN; declara vacías (()) las que no necesites.

Resumen en una tabla

Cabecera Protege contra Valor recomendado
Strict-Transport-Security Conexiones HTTP, degradación de protocolo max-age=31536000; includeSubDomains (+ preload si vas a registrarlo)
Content-Security-Policy Inyección de scripts (XSS), recursos no autorizados Empezar con default-src 'self' y añadir orígenes necesarios
X-Content-Type-Options Interpretación errónea de tipos de archivo nosniff
X-Frame-Options Clickjacking (navegadores antiguos) DENY
Referrer-Policy Fuga de URLs internas a terceros strict-origin-when-cross-origin
Permissions-Policy Uso de APIs sensibles por tu web o iframes Desactivar las que no uses

Dónde se configuran

  • Netlify y Cloudflare Pages: archivo _headers en la carpeta publicada.
  • Vercel: clave headers en vercel.json.
  • Nginx: directivas add_header en el bloque server.
  • Apache: directivas Header set en la configuración o en .htaccess.
  • WordPress: a través del servidor (preferible) o de un plugin de seguridad que las añada.

Lo recomendable es mantenerlas en un único archivo versionado junto al código, para que un cambio en el sitio (por ejemplo, activar publicidad) implique revisar la CSP en el mismo commit.

Cómo comprobarlas

curl -sI https://blog.aimran.es/es/ | grep -iE "strict-transport|content-security|x-content-type|x-frame|referrer-policy|permissions-policy"

Herramientas online como securityheaders.com o el HTTP Observatory de Mozilla analizan la respuesta y puntúan la configuración. Y la consola del navegador mostrará cada violación de CSP con el recurso bloqueado, lo que facilita afinar la política.

Errores habituales

  1. Activar HSTS con preload sin tener todos los subdominios en HTTPS: dejan de funcionar y la reversión tarda meses.
  2. Una CSP con 'unsafe-inline' y 'unsafe-eval' en scripts “para que funcione todo”: cumple el expediente, protege poco.
  3. Olvidar la CSP al añadir un tercero (publicidad, analítica, un widget): el recurso se bloquea en silencio y parece que “no carga”.
  4. Configurar las cabeceras solo en la página de inicio y no en el resto de rutas o en los archivos estáticos.
  5. No probar en modo informe antes de bloquear.

Conclusión

Seis cabeceras, un archivo de configuración y unos minutos: HSTS para forzar HTTPS, CSP para controlar qué se carga, nosniff y X-Frame-Options/frame-ancestors para cerrar vectores clásicos, Referrer-Policy para no filtrar URLs y Permissions-Policy para apagar lo que no usas. Despliega primero la CSP en modo informe, revisa la consola, y versiona las cabeceras junto al código para que evolucionen con el sitio.

Fuentes y referencias

  1. MDN: Strict-Transport-Security developer.mozilla.org
  2. MDN: Content Security Policy (CSP) developer.mozilla.org
  3. MDN: X-Content-Type-Options developer.mozilla.org
  4. MDN: Referrer-Policy developer.mozilla.org
  5. MDN: Permissions-Policy developer.mozilla.org
  6. OWASP Secure Headers Project owasp.org
  7. HSTS Preload List hstspreload.org
Artículos de Tecnología