Las cabeceras de respuesta HTTP indican al navegador cómo tratar sus páginas: qué scripts pueden ejecutarse, si el sitio puede mostrarse dentro de un marco y si debe cargarse siempre por HTTPS. Unas pocas bloquean clases enteras de ataques casi sin coste. Otras están obsoletas y solo añaden ruido, o incluso riesgo.
Una base de partida
Este es un punto de partida razonable para una aplicación HTML servida solo por HTTPS. No lo pegue tal cual. En particular, la CSP debe corresponderse con la forma en que sus páginas cargan los scripts, su nonce debe ser nuevo en cada respuesta, y la precarga de HSTS es difícil de deshacer.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Content-Security-Policy: script-src 'nonce-3f9a1c7e2b' 'strict-dynamic'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), camera=(), microphone=()
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-site
Content-Security-Policy
La CSP limita de dónde pueden proceder los scripts y otros recursos. Su función principal es hacer mucho más difícil explotar el cross-site scripting (XSS).
La hoja de referencia de OWASP sobre CSP prefiere una política estricta basada en nonces o hashes a una larga lista de dominios permitidos. Las políticas de lista de permitidos demasiado amplias o demasiado detalladas suelen acabar eludiéndose. Una política basada en nonces tiene este aspecto:
Content-Security-Policy: script-src 'nonce-3f9a1c7e2b' 'strict-dynamic'; object-src 'none'; base-uri 'none'
Cada etiqueta script lleva entonces el mismo valor, como en <script nonce="3f9a1c7e2b">. El nonce debe ser aleatorio y nuevo en cada respuesta; un valor fijo anula su propósito. Genérelo en la capa de plantillas. OWASP desaconseja el middleware que añade el nonce a todas las etiquetas script, porque también daría por buenos los scripts inyectados.
Si sus páginas son estáticas, use hashes: valores 'sha256-...' para cada script en línea. Cualquier cambio en el script, aunque sea de espacios en blanco, cambia el hash.
Evite 'unsafe-inline' y 'unsafe-eval' en script-src. Vuelven a abrir exactamente lo que la CSP pretende cerrar.
Para desplegarla sin romper nada, envíe primero la política como Content-Security-Policy-Report-Only. Los navegadores notifican las infracciones sin bloquear nada. Corrija lo que muestren los informes y después pase a aplicarla.
Trusted Types
Trusted Types se dirige al XSS basado en DOM, en el que su propio JavaScript pasa cadenas controladas por un atacante a API peligrosas como innerHTML, eval() o el src de un elemento script. Se activa con la CSP:
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types app-policy
Con la aplicación activada, pasar una cadena sin más a uno de estos destinos (sinks) provoca un error. El código debe pasar valores creados por una política con nombre, normalmente una que sanea el HTML. MDN considera la API Baseline desde febrero de 2026, lo que significa que funciona en las versiones actuales de los principales navegadores. Empiece en modo report-only, ya que el código existente puede escribir cadenas directamente en el DOM.
Strict-Transport-Security y la precarga
HSTS indica a los navegadores que se conecten a su dominio solo por HTTPS durante el número de segundos de max-age. Con includeSubDomains, la regla abarca también todos los subdominios.
La lista de precarga va más allá. Los navegadores incorporan la lista, de modo que incluso la primera visita a su dominio usa HTTPS. Los requisitos de hstspreload.org son:
- un certificado válido y una redirección de HTTP a HTTPS en el mismo host
- todos los subdominios servidos por HTTPS, incluidos los internos
- un
max-agede al menos 31536000 (un año), másincludeSubDomainsypreload - la cabecera HSTS también en las redirecciones servidas desde el sitio HTTPS
Despliéguelo por fases. El sitio de la lista de precarga sugiere empezar con max-age=300, pasar después a una semana (604800) y luego a un mes (2592000), vigilando si algo se rompe en cada paso. Salir de la lista de precarga tarda meses en llegar a los usuarios, así que asegúrese de que todos los subdominios pueden admitir HTTPS a largo plazo.
X-Content-Type-Options
X-Content-Type-Options: nosniff impide que los navegadores adivinen el tipo de un archivo a partir de su contenido. Combínela con un Content-Type correcto en cada respuesta, incluido un charset para el HTML, como text/html; charset=UTF-8.
frame-ancestors y X-Frame-Options
El clickjacking consiste en cargar su página de forma invisible dentro de un marco en otro sitio. La directiva CSP frame-ancestors controla quién puede enmarcar su página, y OWASP señala que sustituye a X-Frame-Options en los navegadores que la admiten.
Hay dos detalles que suelen pillar por sorpresa. Según MDN, frame-ancestors no recurre a default-src como valor por defecto, así que debe fijarla de forma explícita. Además, no tiene efecto en una etiqueta <meta>; solo funciona como cabecera. Para los navegadores antiguos, no está de más enviar ambas:
Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY
Use frame-ancestors 'self' si su propio sitio enmarca sus páginas. Evite X-Frame-Options: ALLOW-FROM, que está obsoleta. MDN señala que los navegadores modernos ignoran toda la cabecera cuando la encuentran.
Referrer-Policy
Esta cabecera controla qué parte de la URL actual se envía a otros sitios en la cabecera Referer. Si no fija nada, los navegadores usan por defecto strict-origin-when-cross-origin, que solo envía el origen a otros sitios por HTTPS. Aun así, OWASP recomienda fijarla de forma explícita. Use no-referrer o same-origin si sus URL pueden contener tokens o datos personales.
Permissions-Policy
Permissions-Policy desactiva las funciones del navegador que su sitio no usa. Una lista de permitidos vacía, (), desactiva una función para su página y para todos los marcos que contenga:
Permissions-Policy: geolocation=(), camera=(), microphone=(), payment=()
Si necesita una función, permítala de forma restringida, por ejemplo camera=(self).
COOP y CORP
Cross-Origin-Opener-Policy: same-origin coloca su página en su propio grupo de contextos de navegación. Así, una página que abra la suya con window.open() no puede conservar una referencia a ella, lo que cierra la puerta a una clase de ataques de fuga entre sitios (XS-Leaks). Si depende de ventanas emergentes para el inicio de sesión único o los pagos, same-origin-allow-popups hace que sigan funcionando.
Cross-Origin-Resource-Policy: same-site impide que otros sitios incrusten sus recursos, como imágenes o scripts. Cross-Origin-Embedder-Policy: require-corp solo es necesaria para el aislamiento entre orígenes, que exigen funciones como SharedArrayBuffer. No incluya COEP salvo que necesite esas funciones, porque bloquea los recursos de otros orígenes que no lo autoricen expresamente.
Cabeceras que conviene retirar
| Cabecera | Situación | Qué hacer |
|---|---|---|
X-XSS-Protection | Obsoleta y no estándar; MDN advierte de que puede crear fallos XSS en sitios que, por lo demás, son seguros | Elimínela o envíe 0, y confíe en la CSP |
Expect-CT | Obsoleta | Elimínela |
Public-Key-Pins | Eliminada de Chromium en 2018 | Elimínela; use en su lugar Certificate Transparency y registros CAA |
X-Frame-Options: ALLOW-FROM | Obsoleta | Use frame-ancestors |
Server, X-Powered-By | Revelan el software y sus versiones | Elimínelas o use un valor neutro |
Por dónde empezar
- Compruebe lo que envía hoy su sitio con nuestro escáner de cabeceras de seguridad.
- Añada primero las cabeceras de bajo riesgo:
X-Content-Type-Options,Referrer-Policy,Permissions-Policyyframe-ancestors. - Despliegue HSTS con un
max-agecorto y auméntelo por fases. Plantéese la precarga solo cuando todos los subdominios estén preparados. - Mantenga la CSP en modo report-only durante unas semanas, corrija las infracciones y después aplíquela.
Si está desarrollando una aplicación nueva y quiere que todo esto se diseñe desde el principio, nuestro equipo de desarrollo de software seguro puede ayudarle.
