Cabeceras HTTP de seguridad: CSP, HSTS y las demás

Qué cabeceras HTTP de seguridad configurar, con valores de partida, qué rompe cada una si te equivocas y cómo implantar la CSP sin tumbar el sitio.

Verificar mi sitio gratisVer los planes
En esta página 11 min de lectura
  1. Resumen: valores de partida y qué puede romperse
  2. Strict-Transport-Security (HSTS)
  3. Content-Security-Policy (CSP)
  4. X-Content-Type-Options
  5. Referrer-Policy
  6. Permissions-Policy
  7. X-Frame-Options o frame-ancestors
  8. Cross-Origin-Opener-Policy y Cross-Origin-Resource-Policy
  9. Cabeceras que ya no deben usarse
  10. Un conjunto inicial completo
  11. Cómo verificar tu sitio

Las cabeceras HTTP de seguridad que sirven para casi cualquier sitio son: Strict-Transport-Security (obliga a usar HTTPS), Content-Security-Policy (limita los scripts y quién puede mostrar la página en un iframe), X-Content-Type-Options: nosniff, Referrer-Policy y Permissions-Policy. X-Frame-Options todavía sirve de respaldo para navegadores antiguos, y Cross-Origin-Opener-Policy y Cross-Origin-Resource-Policy aíslan la página de otros sitios. X-XSS-Protection, Expect-CT y Feature-Policy ya no deben usarse. La CSP es la que más trabajo da y la que más rompe; conviene empezarla en modo de informe.

Este texto cubre el comportamiento de los navegadores y las recomendaciones de MDN, OWASP y el W3C en octubre de 2026. Forma parte de la guía de seguridad básica de un sitio web, que trata HTTPS, archivos expuestos, versiones y cookies.

Resumen: valores de partida y qué puede romperse

Los valores de abajo son un punto de partida habitual, basado en las referencias citadas en cada sección. No son los únicos correctos: cada sitio tiene que ajustarlos según lo que usa.

CabeceraValor de partidaQué puede romperse
Strict-Transport-Securitymax-age=63072000; includeSubDomainsLos subdominios que todavía no tienen HTTPS quedan inaccesibles
Content-Security-PolicyPolítica con nonce, object-src 'none', base-uri 'none' y frame-ancestorsScripts inline, eventos onclick, eval(), widgets de terceros
X-Content-Type-OptionsnosniffScripts y CSS servidos con un Content-Type incorrecto
Referrer-Policystrict-origin-when-cross-originHerramientas que dependen de la ruta completa de origen en otro dominio
Permissions-Policycamera=(), microphone=(), geolocation=()Funciones que el sitio o un iframe de un socio usan de verdad
X-Frame-OptionsDENY o SAMEORIGINLa visualización legítima del sitio dentro de iframes
Cross-Origin-Opener-Policysame-origin, o same-origin-allow-popups si hay login o pago en ventana emergenteVentanas emergentes de OAuth y de pago que se comunican con la ventana que las abrió
Cross-Origin-Resource-Policysame-siteArchivos de tu dominio que usan otros sitios

Strict-Transport-Security (HSTS)

HSTS le dice al navegador que a ese host solo se puede acceder por HTTPS durante max-age segundos. Después de recibir la cabecera, el navegador convierte por su cuenta las peticiones http en https y no deja que el usuario ignore errores de certificado (MDN: Strict-Transport-Security). Hay tres detalles que importan:

  • La cabecera solo vale si llega en una respuesta HTTPS; enviada por http, se ignora.

  • Solo protege a partir de la segunda visita, porque el navegador tiene que haber recibido la cabecera una vez. La lista de precarga de los navegadores (preload) cierra ese hueco.

  • includeSubDomains extiende la regla a todos los subdominios, presentes y futuros.

Strict-Transport-Security: max-age=63072000; includeSubDomains

Mozilla recomienda como mínimo seis meses y sugiere dos años (63072000) (MDN: guía práctica de TLS); ASVS 5.0 pide como mínimo un año y, desde el nivel 2, incluir los subdominios (ASVS 5.0, requisito 3.4.1). Recomendación de implantación: empieza con un max-age corto, comprueba que todo funciona y solo entonces súbelo, porque el navegador recordará la regla durante todo el plazo. OWASP advierte que un HSTS mal configurado o un problema de certificado puede dejar a los usuarios sin acceso durante todo el max-age (OWASP HTTP Headers Cheat Sheet).

Para entrar en la lista de precarga, el sitio necesita un certificado válido, redirigir http a https en el mismo host, tener HTTPS en todos los subdominios y enviar un max-age de al menos un año con includeSubDomains y preload. Salir de la lista es lento (puede tardar meses en llegar a los usuarios) y los demás navegadores no tienen obligación de seguir la eliminación (hstspreload.org). Haz la solicitud solo si todos los subdominios, incluidos los internos, van a seguir en HTTPS a largo plazo.

Content-Security-Policy (CSP)

La CSP es una lista de reglas que le dice al navegador de dónde puede la página cargar scripts, estilos, imágenes e iframes y adónde puede enviar datos. Su uso principal es reducir el efecto del XSS (cross-site scripting, la inyección de script en la página): aunque un atacante logre insertar un <script>, el navegador no lo ejecuta si no cumple la política. Es una capa más y no sustituye la corrección de los fallos de XSS (web.dev: strict CSP).

Lista de dominios o política estricta con nonce

Hay dos formas de escribir la regla de scripts. La antigua es enumerar los dominios permitidos (script-src 'self' https://cdn.ejemplo.com). La que recomiendan MDN y web.dev es la llamada CSP estricta, basada en nonce o hash (MDN: guía de CSP; web.dev: strict CSP). ASVS 5.0 acepta las dos formas en el nivel 2, siempre que la política tenga object-src 'none' y base-uri 'none', y exige nonce o hash por respuesta en el nivel 3 (ASVS 5.0, requisito 3.4.3).

Un nonce es un valor aleatorio que el servidor genera en cada respuesta, pone en la cabecera y repite en el atributo nonce de cada <script> legítimo. El navegador solo ejecuta los scripts que llevan el valor correcto. El nonce tiene que ser impredecible y distinto en cada respuesta, y debe insertarlo el sistema de plantillas, nunca en todos los <script> de la página de forma indiscriminada, para no sellar también un script inyectado (MDN: guía de CSP).

Content-Security-Policy:
  script-src 'nonce-R4nd0mPorRespuesta' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';
  frame-ancestors 'self'

<script nonce="R4nd0mPorRespuesta" src="/js/app.js"></script>

'strict-dynamic' hace que también se ejecuten los scripts creados por un script que ya es de confianza. Así las bibliotecas y los widgets de terceros pueden cargar sus propios archivos sin que tengas que enumerar cada dominio (web.dev: strict CSP). Para páginas estáticas o servidas desde caché, web.dev recomienda hash en lugar de nonce: 'sha256-...' calculado sobre el contenido de cada script inline. Un nonce guardado en una página en caché se repite para todos los visitantes y pierde el sentido.

frame-ancestors

La directiva frame-ancestors define qué páginas pueden mostrar el sitio dentro de un <iframe>, lo que protege contra el clickjacking (cuando otro sitio muestra el tuyo por debajo de botones falsos). MDN recomienda 'none' para sitios que no necesitan incrustarse (MDN: guía de CSP). No hereda el valor de default-src y no funciona en metaetiqueta (MDN: frame-ancestors).

Content-Security-Policy: frame-ancestors 'none'
Content-Security-Policy: frame-ancestors 'self' https://socio.ejemplo.com

Modo de solo informe

La cabecera Content-Security-Policy-Report-Only aplica la misma sintaxis sin bloquear nada: el navegador solo registra y envía las infracciones (MDN: Content-Security-Policy-Report-Only). Las dos cabeceras pueden enviarse juntas; en ese caso se aplica la política normal y la de informe solo genera avisos, lo que permite probar una versión más estricta sin tocar la que está en vigor (MDN: guía de CSP).

Los informes van a la dirección definida en la cabecera Reporting-Endpoints y referenciada por la directiva report-to. La directiva antigua report-uri está obsoleta, pero MDN recomienda declarar las dos mientras report-to no funcione en todos los navegadores (MDN: guía de CSP; W3C: CSP Level 3).

Reporting-Endpoints: csp="https://ejemplo.com/csp-informes"
Content-Security-Policy-Report-Only:
  script-src 'nonce-R4nd0mPorRespuesta' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';
  report-uri https://ejemplo.com/csp-informes;
  report-to csp

Cómo implantar la CSP sin tumbar el sitio

  1. Haz una lista de los scripts y recursos de cada tipo de página (inicio, producto, checkout, área privada) con la pestaña Network de DevTools.

  2. Elige nonce si las páginas se generan en el servidor en cada petición, o hash si son estáticas o se sirven desde caché (web.dev).

  3. Ajusta el código que la política va a bloquear: cambia los eventos inline como onclick por addEventListener, cambia los enlaces javascript: por eventos y sustituye eval() (por ejemplo, por JSON.parse()) (web.dev).

  4. Publica la política en Content-Security-Policy-Report-Only con un endpoint de informes.

  5. Sigue los informes el tiempo suficiente para cubrir todos los tipos de página y flujos, incluidos el checkout y las campañas de temporada, y corrige o permite cada origen legítimo.

  6. Cambia a Content-Security-Policy y mantén el envío de informes.

  7. Revisa la política en CSP Evaluator o en Lighthouse antes y después del cambio, como sugiere web.dev.

Lo que suele romperse

  • Scripts inline sin nonce ni hash, incluidos los que imprimen en la página los plugins y temas.

  • Atributos de evento (onclick, onload) y enlaces javascript:, que la CSP estricta bloquea.

  • Bibliotecas que usan eval() o new Function(). Permitirlas con 'unsafe-eval' debilita la política (web.dev).

  • Un nonce en una página guardada en caché, que repite el valor y hace que fallen scripts o deja la protección sin efecto.

  • Con una política de lista de dominios: cualquier origen nuevo (un píxel, un chat, una fuente) queda bloqueado hasta que alguien actualice la lista.

X-Content-Type-Options

Con nosniff, el navegador deja de adivinar el tipo del archivo por su contenido y usa el Content-Type declarado. Las peticiones de script se bloquean si el tipo no es de JavaScript, y las de hoja de estilo si no es text/css. Esto evita, por ejemplo, que un archivo subido por un usuario como texto se ejecute como HTML o script (MDN: X-Content-Type-Options). ASVS pide la cabecera en todas las respuestas (requisito 3.4.4).

X-Content-Type-Options: nosniff

Lo que se rompe: archivos servidos con un tipo incorrecto, como un .js entregado como text/plain. Antes de activarla, revisa el Content-Type de tus scripts y CSS, sobre todo los que se generan de forma dinámica.

Referrer-Policy

La cabecera Referer le dice al sitio de destino de dónde viene el visitante. Si la dirección lleva datos en la ruta o en la query string (un token, un correo, un número de pedido), esos datos se filtran a terceros. Referrer-Policy controla cuánto de esa dirección se envía. Cuando el sitio no define nada, el valor por defecto de los navegadores hoy es strict-origin-when-cross-origin: la dirección completa para el propio sitio, solo el origen para otros sitios en HTTPS y nada cuando la conexión baja a HTTP (MDN: Referrer-Policy).

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

OWASP recomienda declarar la cabecera en vez de depender del valor por defecto del navegador y usa ese valor como ejemplo (OWASP HTTP Headers Cheat Sheet); la lista de valores de OWASP Secure Headers Project va más allá y sugiere no-referrer (headers_add.json). no-referrer es más restrictivo, pero puede estorbar a las herramientas de analítica que dependen del origen del tráfico. Evita unsafe-url, que envía la dirección completa incluso a destinos en HTTP.

Permissions-Policy

Permissions-Policy activa o desactiva funciones del navegador, como la cámara, el micrófono, la geolocalización y el pago, para la página y para los iframes que contiene. () desactiva la función en todas partes; self la permite solo para el mismo origen; un origen entre comillas la permite para ese dominio (MDN: Permissions-Policy).

Permissions-Policy: camera=(), microphone=(), geolocation=()
Permissions-Policy: geolocation=(self "https://mapas.ejemplo.com"), microphone=()

La recomendación de OWASP es desactivar todo lo que el sitio no usa (OWASP HTTP Headers Cheat Sheet). MDN marca la cabecera como experimental y dice que no funciona en algunos navegadores muy usados, así que trátala como una protección adicional, no como la única barrera. Lo que se rompe: un iframe de un socio (mapa, vídeo, pago) que necesita una función desactivada. En el iframe, el atributo allow concede la función dentro del límite que permite la cabecera.

X-Frame-Options o frame-ancestors

X-Frame-Options fue la primera cabecera contra el clickjacking. Acepta DENY (nadie muestra la página en un iframe) y SAMEORIGIN (solo páginas del mismo origen). El valor ALLOW-FROM está obsoleto y hace que los navegadores modernos ignoren la cabecera entera, y la cabecera no tiene efecto en metaetiqueta (MDN: X-Frame-Options).

La directiva frame-ancestors de la CSP hace lo mismo con más opciones, como permitir dominios concretos. La especificación de la CSP define que, cuando se aplica una política con frame-ancestors, el navegador ignora X-Frame-Options (W3C: CSP Level 3, sección 6.4.2.2). ASVS 5.0 trata X-Frame-Options como obsoleta y pide frame-ancestors (requisito 3.4.6). Recomendación: usa frame-ancestors como regla principal y mantén un X-Frame-Options coherente para navegadores antiguos. No molesta a los nuevos, que en ese caso ya lo ignoran.

Cross-Origin-Opener-Policy y Cross-Origin-Resource-Policy

Cross-Origin-Opener-Policy (COOP) decide si tu página comparte el contexto de navegación con ventanas de otros sitios que ella abrió o que la abrieron. Con same-origin, una ventana de otro dominio queda aislada y pierde la referencia window.opener. Eso rompe los flujos de login (OAuth) y de pago en ventana emergente que devuelven el resultado a la ventana original; para esos casos existe same-origin-allow-popups (MDN: Cross-Origin-Opener-Policy). ASVS pide uno de los dos valores en las respuestas que abren documentos (requisito 3.4.8).

Cross-Origin-Opener-Policy: same-origin-allow-popups

Cross-Origin-Resource-Policy (CORP) va en el recurso, no en la página. Dice qué orígenes pueden cargar ese archivo en peticiones sin CORS, como <img> y <script>: same-origin, same-site o cross-origin (MDN: Cross-Origin-Resource-Policy). Mozilla incluye CORP entre las protecciones contra ataques de canal lateral especulativo (MDN: guías prácticas), y OWASP sugiere same-site. Lo que se rompe: imágenes, fuentes o scripts de tu dominio que usan otros sitios, como un widget que distribuyes. Esos archivos necesitan cross-origin.

La pareja Cross-Origin-Embedder-Policy: require-corp con COOP same-origin activa el aislamiento entre orígenes, necesario para funciones como SharedArrayBuffer (MDN). COEP bloquea los recursos de otros orígenes que no autoricen su uso por CORP o CORS (OWASP). Opinión: en un sitio corporativo o una tienda que no necesita ese aislamiento, COEP suele costar más (anuncios, vídeos y widgets bloqueados) de lo que aporta.

Cabeceras que ya no deben usarse

CabeceraSituaciónQué hacer
X-XSS-ProtectionFuera de cualquier especificación y obsoleta. MDN advierte que el filtro puede crear fallos de XSS en sitios que no los tenían (MDN)No enviarla, o enviar 0 para desactivar el filtro, como sugiere OWASP; proteger con CSP
Expect-CTSolo la implementó Chromium, que la considera obsoleta desde la versión 107 porque ya exige Certificate Transparency por defecto (MDN)Quitarla
Feature-PolicyRenombrada como Permissions-Policy, con otra sintaxis. En Chrome funciona solo como alias, y Permissions-Policy prevalece cuando llegan las dos (Chrome for Developers)Migrar a Permissions-Policy
Public-Key-PinsOWASP recomienda no usarla y quitarla de producción (OWASP)Quitarla

Un conjunto inicial completo

Un ejemplo para un sitio servido de forma dinámica, que otros sitios no incrustan y con pago en ventana emergente. La forma de configurarlo depende del servidor (nginx, Apache), del CDN o del framework; el contenido de las cabeceras es el mismo.

Strict-Transport-Security: max-age=63072000; includeSubDomains
Content-Security-Policy: script-src 'nonce-{generado por respuesta}' 'strict-dynamic'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; report-to csp
Reporting-Endpoints: csp="https://ejemplo.com/csp-informes"
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
X-Frame-Options: DENY
Cross-Origin-Opener-Policy: same-origin-allow-popups

Para comparar, OWASP Secure Headers Project publica una lista más estricta y actualizada con frecuencia, pensada como referencia máxima y no como configuración para copiar sin probar (headers_add.json).

Cómo verificar tu sitio

En la terminal, curl -sI https://ejemplo.com/ muestra las cabeceras de una respuesta. Repítelo con una página interna, un archivo de imagen y una respuesta de error, porque los servidores y los CDN no siempre aplican las mismas cabeceras a todo. HTTP Observatory de Mozilla da una nota y explica cada punto. La auditoría de WebVyze señala la falta de HSTS, CSP, X-Content-Type-Options y Referrer-Policy, la CSP que existe pero no frena scripts inyectados y la página que otros sitios pueden incrustar, cada una con su guía de corrección. En las tiendas, la CSP de la página de pago también cuenta para PCI DSS; el artículo sobre los requisitos 6.4.3 y 11.6.1 explica cómo, y los planes de pago de WebVyze mantienen un inventario de los scripts de las páginas de checkout. WebVyze solo lee páginas públicas y no modifica nada en el sitio.

Preguntas frecuentes

¿Puedo poner la CSP en una metaetiqueta en lugar de en la cabecera?
Sí, con límites. La especificación ignora las directivas frame-ancestors, report-uri y sandbox cuando la política viene de una metaetiqueta, y el modo de solo informe (Content-Security-Policy-Report-Only) no funciona en metaetiqueta. Para una política completa, usa la cabecera.
¿Las cabeceras tienen que estar en todas las respuestas o solo en las páginas HTML?
Depende de la cabecera. ASVS 5.0 pide HSTS, nosniff y frame-ancestors en todas las respuestas y Cross-Origin-Opener-Policy en las respuestas que abren un documento, como las páginas HTML. Configurarlas en el servidor o en el CDN para todas las respuestas suele ser lo más sencillo.
¿Quitar las cabeceras Server y X-Powered-By mejora la seguridad?
Dificulta identificar la tecnología que usas, y OWASP recomienda quitar esas cabeceras o dejarlas sin información útil. No impide que alguien descubra la tecnología por otras vías y no te ahorra las actualizaciones.
¿Cómo recibo los informes de infracción de la CSP?
El navegador envía un POST en JSON a la dirección declarada en Reporting-Endpoints (directiva report-to) o en report-uri. Necesitas un endpoint que acepte y guarde esos envíos: un servicio propio sencillo o una herramienta de terceros.
Sobre el autor

Daniel Paz

Especialista en WordPress, rendimiento y SEO, fundador de WebOption

Daniel Paz es especialista en WordPress, rendimiento y SEO, fundador de WebOption y conferencista internacional. Con más de 18 años de experiencia en desarrollo web, ayuda a empresas a convertir sus sitios en plataformas rápidas, eficientes y orientadas a resultados.

Vea lo que su sitio necesita corregir.

Una verificación gratuita por ley, con la causa y la guía de corrección de cada problema.

Verificar mi sitio gratisCrear una cuenta gratis

Siga leyendo

Socios

Beneficios de socios con un solo cupón.

WPLIGHT

Enlaces de socios. Podemos recibir una comisión, sin costo adicional para ti.