Cabeceras de seguridad
Las cabeceras de seguridad son líneas en la respuesta de tu servidor web que le dicen al navegador qué debe rechazar: adivinar tipos de archivo, mostrar tus páginas dentro de marcos ajenos, pasar direcciones completas a otros sitios, volver a HTTP o cargar scripts de hosts desconocidos. Hive las define por ti, genera la configuración del servidor web correspondiente y comprueba lo que llega de verdad al visitante. Esta página explica cada cabecera, las tres vías que puede tomar y qué hacer cuando la comprobación señala un problema.
Qué incluye cada plan
Todos los ajustes de cabeceras están en Ajustes de protección → Cortafuegos y bots → Cabeceras de seguridad. El interruptor principal Enviar cabeceras de seguridad está desactivado tras la instalación; la recomendación del inicio rápido lo activa. Las tres cabeceras básicas forman parte del plugin gratuito. Las cabeceras avanzadas llegan con el complemento Pro a partir del plan Professional y funcionan tanto en Local Shield como en la Community Network.
| Cabecera | Plan | Valor tras la instalación |
|---|---|---|
X-Content-Type-Options | Gratis | nosniff |
X-Frame-Options | Gratis | SAMEORIGIN |
Referrer-Policy | Gratis | strict-origin-when-cross-origin |
Strict-Transport-Security (HSTS) | Desde Professional | Desactivado; la recomendación para Professional lo activa, sin preload |
Permissions-Policy | Desde Professional | geolocation=(), camera=(), microphone=(), payment=(), usb=(), magnetometer=() |
Content-Security-Policy | Desde Professional | Desactivado, política vacía |
Cross-Origin-Opener-Policy, -Resource-Policy, -Embedder-Policy | Desde Professional | Desactivado |
Cada cabecera solo se envía mientras Enviar cabeceras de seguridad está activado. Cuando termina un plan, Hive deja de enviar las cabeceras avanzadas y mantiene las tres básicas. Las cabeceras que hayas copiado en la configuración del servidor web no se ven afectadas por ninguno de los dos casos: el servidor las sigue enviando hasta que las quites de allí.
Tres vías hasta el visitante
El bloque Cómo llegan las cabeceras a tus visitantes, encima de las filas de cabeceras, muestra el estado de cada vía en tu sitio.
- Configuración del servidor web. nginx o Apache añaden las cabeceras a cada respuesta: páginas de una caché, imágenes, archivos CSS y JavaScript, la página de acceso y las páginas de error. Es la vía más compatible. Hive genera la configuración a partir de tus ajustes.
- Protección ampliada. El cortafuegos que se ejecuta antes de WordPress (ver Cortafuegos y WAF) también envía las cabeceras. Alcanza las páginas que un plugin de caché entrega a través de PHP, por ejemplo desde
advanced-cache.php. Solo actúa en peticiones al sitio público que pasan porindex.php, no en wp-admin, y envía HSTS solo por HTTPS. - Solo WordPress. Hive añade las cabeceras a cada página pública que genera WordPress. Las páginas de una caché, los archivos estáticos y todo lo que el servidor web responde por su cuenta salen sin ellas.
| Tu entorno | Vía a usar |
|---|---|
| Sin caché de páginas | Basta con WordPress. Activa las cabeceras y lanza la comprobación. |
| Plugin de caché que sirve las páginas a través de PHP (WP Rocket, WP Super Cache, W3 Total Cache y otros en su configuración habitual) | Protección ampliada, o la configuración del servidor web |
Caché servida por el servidor web sin PHP: Rocket-Nginx, reglas de reescritura estáticas en el .htaccess, una caché del panel de hosting | Solo la configuración del servidor web |
| Quieres las cabeceras también en imágenes, archivos y la página de acceso | Solo la configuración del servidor web |
| Hosting sin acceso a la configuración del servidor | Apache con .htaccess: las líneas de Apache; si no, Protección ampliada |
Elijas lo que elijas, define cada cabecera en un solo lugar. Una cabecera que el servidor web añade por su cuenta es invisible para WordPress, así que Hive no puede omitirla, y entonces llega dos veces. La comprobación de cabeceras lo detecta.
Configuración paso a paso
Activar las cabeceras
Abre Ajustes de protección → Cortafuegos y bots → Cabeceras de seguridad, activa Enviar cabeceras de seguridad y deja las tres cabeceras básicas en sus valores recomendados. Haz clic en Guardar cambios. Todas las filas de cabeceras, el interruptor incluido, están detrás de Mostrar detalles técnicos; el modo experto las abre por defecto.
Añadir las cabeceras avanzadas (complemento Pro)
Activa HTTP Strict Transport Security con un max-age de HSTS (segundos) de 300 durante los primeros días. Compara la Permissions-Policy con las funciones que usa tu sitio. Pon la Content-Security-Policy en modo Solo informe, como se describe más abajo. Deja por ahora desactivadas las cabeceras Cross-Origin. Guarda.
Lanzar la comprobación de cabeceras
Abre Configuración del servidor y comprobación de cabeceras y haz clic en Comprobar las cabeceras de la página de inicio. Si cada fila dice Llega una vez, tal como se define aquí, la entrega está resuelta. Cualquier otro resultado se explica en La comprobación de cabeceras.
Cerrar el hueco en las páginas en caché
Si la comprobación muestra Falta en las páginas en caché, activa la Protección ampliada en Servidor & mantenimiento → Servidor y vuelve a comprobar. Si las cabeceras siguen faltando, tu caché entrega las páginas sin PHP; sigue con el paso 5.
Pasar las cabeceras al servidor web (opcional)
Copia las líneas generadas para nginx o Apache en la configuración del servidor y recarga el servidor web. Después desactiva Enviar cabeceras de seguridad en Hive y guarda. Vuelve a comprobar: cada cabecera debería mostrar ahora Definida por el servidor web u otro plugin, que es el resultado correcto para esta vía.
Subir HSTS y aplicar la CSP
Tras unos días sin problemas, sube el max-age de HSTS a 31536000 (un año). Pasa la Content-Security-Policy a Aplicar cuando la consola del navegador quede limpia en cada tipo de página.
Cada cabecera en detalle
| Cabecera | Protege contra | Recomendado | Puede romper |
|---|---|---|---|
X-Content-Type-Options | MIME sniffing: un archivo subido que dice ser una imagen se ejecuta como script | Activado, nosniff | Prácticamente nada |
X-Frame-Options | Clickjacking: un sitio ajeno muestra tu página en un marco invisible y engaña a los visitantes para que hagan clic | SAMEORIGIN | DENY bloquea también los marcos entre tus propias páginas; cualquier valor impide la incrustación en otros dominios |
Referrer-Policy | Rutas y parámetros de tus direcciones filtrados a otros sitios | strict-origin-when-cross-origin | no-referrer te oculta en las estadísticas de referencia de los sitios asociados |
Strict-Transport-Security | Vuelta a HTTP y SSL stripping en redes abiertas | 300 para probar, luego 31536000 | Cualquier página o archivo que aún cargue por HTTP; con includeSubDomains, cualquier subdominio sin certificado válido |
Permissions-Policy | Funciones del navegador usadas por un script inyectado | Desactivar lo que no uses | Buscador de tiendas (geolocation), Apple Pay y Google Pay (payment), videollamadas (camera, microphone) |
Content-Security-Policy | Cross-site scripting y scripts inyectados | Primero Solo informe, cada servicio externo en la lista, luego Aplicar | Scripts del tema, seguimiento, herramienta de consentimiento, vídeos y mapas incrustados |
Cross-Origin-Opener-Policy | Ataques a través de ventanas que tus páginas abren o que las abren | same-origin si no usas ventanas de acceso o de pago de otros dominios | Ventanas de PayPal, Google y acceso con redes sociales |
Cross-Origin-Resource-Policy | Otros sitios que cargan tus imágenes y scripts en sus páginas | same-origin solo sin un nombre de host de CDN | Enlaces directos y archivos que tus páginas cargan desde otro nombre de host propio, como un CDN |
Cross-Origin-Embedder-Policy | Solo necesaria para funciones especiales del navegador (SharedArrayBuffer, temporizadores precisos) | Desactivada, salvo que un desarrollador la pida | La mayoría del contenido de terceros incrustado: vídeos, mapas, fuentes web |
Así se ven las cabeceras en una respuesta:
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
Strict-Transport-Security: max-age=31536000; includeSubDomains
Permissions-Policy: geolocation=(), camera=(), microphone=(), payment=(), usb=()
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-origin
HSTS. En cuanto un navegador ha visto la cabecera, se conecta solo por HTTPS durante el tiempo que
indica max-age, y no puedes deshacerlo para los visitantes que ya la tienen. Actívala solo cuando cada
página y cada archivo carguen por HTTPS. El valor guardado por defecto es 63072000 (dos años), que
también es el límite superior; empieza con 300 (cinco minutos). HSTS includeSubDomains
extiende la regla a cada subdominio, incluidos los de correo y tienda. HSTS preload pide a los
navegadores que incluyan tu dominio en su lista integrada (hstspreload.org); requiere includeSubDomains y al menos
un año, y salir de la lista lleva meses. Hive envía HSTS solo por HTTPS. Detrás de un proxy que termina TLS,
WordPress tiene que reconocer la petición como HTTPS; si no, Hive omite HSTS.
Permissions-Policy. feature=() desactiva una función, feature=(self) la
permite solo en tus propias páginas. El valor por defecto desactiva payment; una tienda con botones de
Apple Pay o Google Pay necesita payment=(self) o quitar la entrada; si no, los botones no aparecen.
X-Frame-Options y la CSP. Los navegadores actuales siguen primero la directiva
frame-ancestors de una Content-Security-Policy aplicada. X-Frame-Options se mantiene para navegadores
antiguos; mantén ambas en la misma línea, por ejemplo SAMEORIGIN y frame-ancestors 'self'.
La Content-Security-Policy paso a paso
Una CSP es una lista de fuentes desde las que el navegador puede cargar scripts, estilos, imágenes, fuentes, marcos y
conexiones. Todo lo demás se rechaza. Es la cabecera más fuerte y la que más rompe, por eso tiene dos modos:
Solo informe envía la política como Content-Security-Policy-Report-Only, no se bloquea
nada y cada infracción aparece en la consola del navegador. Aplicar envía
Content-Security-Policy y bloquea.
- Empezar con la política inicial para WordPress. Pon el Modo de Content-Security-Policy en Solo informe y pega la política de abajo en Content-Security-Policy. Encaja con un sitio WordPress sin servicios externos. La mayoría de los temas necesitan
'unsafe-inline'para scripts y estilos, por eso está incluido. - Abrir cada tipo de página. Página de inicio, una entrada, una página, el formulario de contacto, la tienda, el carrito y la caja, con el banner de cookies aceptado, porque el seguimiento y el contenido incrustado a menudo solo cargan tras el consentimiento. Abre la consola del navegador con F12; allí aparece cada fuente que la política no permite, con la directiva infringida.
- Añadir cada fuente externa a su directiva. Un host de scripts va en
script-src, un host al que la página envía datos enconnect-src, un marco de vídeo o mapa enframe-src, un host de fuentes enfont-src. Separa las directivas con punto y coma y los hosts con espacios. Guarda, recarga y repite hasta que la consola quede limpia. - Pasar a Aplicar. Pon el modo en Aplicar, abre otra vez los tipos de página y vigila formularios y caja durante unos días.
La política inicial para WordPress que trae el plugin:
default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'
Ejemplo: Google Tag Manager con Google Analytics 4. El gestor de etiquetas carga su script desde
www.googletagmanager.com, y Analytics envía sus mediciones a dos familias de hosts de Google. Añádelos a
script-src y connect-src:
default-src 'self'; script-src 'self' 'unsafe-inline' https://www.googletagmanager.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://*.google-analytics.com https://*.analytics.google.com; frame-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'
Cada etiqueta adicional del contenedor trae sus propios hosts, que la consola nombra. En la política inicial,
img-src ya permite imágenes de cualquier host HTTPS, así que los píxeles de seguimiento no necesitan
entrada allí. En modo Solo informe los navegadores ignoran frame-ancestors; X-Frame-Options lo cubre
hasta que apliques la política.
URI de informes CSP. Opcional. Una dirección HTTPS que recibe cada infracción como informe JSON.
Hive la envía como report-uri y, para navegadores actuales, como report-to csp-endpoint
junto con una cabecera Reporting-Endpoints:
Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri https://example.com/csp-report; report-to csp-endpoint
Reporting-Endpoints: csp-endpoint="https://example.com/csp-report"
Privacidad: cada informe contiene la dirección IP del visitante y la dirección que visitó. Un servicio externo de informes trata por tanto datos personales por encargo tuyo, necesita un contrato de encargo de tratamiento y debe figurar en tu política de privacidad. Para la mayoría de los sitios basta con la consola del navegador durante la fase de solo informe; en ese caso deja el campo vacío.
La configuración del servidor web generada
En Configuración del servidor y comprobación de cabeceras, Hive muestra la configuración para nginx y para Apache, generada a partir de los ajustes guardados, cada una con un botón Copiar. Tras un cambio, guarda primero. Con Enviar cabeceras de seguridad desactivado no hay nada que generar: actívalo, guarda, copia y vuelve a desactivarlo cuando la configuración esté activa. Guarda una copia de las líneas, porque cada cambio posterior requiere los mismos pasos. Con las tres cabeceras básicas y HSTS, el resultado es este:
# ReportedIP Hive: security headers for nginx.
# Paste into the server { } block that serves HTTPS, then run: nginx -t && systemctl reload nginx
# A location { } block with its own add_header inherits none of these lines.
# Repeat them there, or keep them in one file and include it in both places.
# Afterwards switch off "Send security headers" in Hive, otherwise every header is sent twice.
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000" always;
# ReportedIP Hive: security headers for Apache (.htaccess or virtual host).
# Afterwards switch off "Send security headers" in Hive, otherwise every header is sent twice.
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Strict-Transport-Security "max-age=31536000" "expr=%{HTTPS} == 'on'"
</IfModule>
En qué fijarse:
always. Sin él, nginx solo añade cabeceras a las respuestas correctas. Con él llegan también a las páginas de error y a las redirecciones.- Los bloques location no heredan. nginx solo pasa las líneas
add_headera los bloques que no tienen ninguna propia. Un bloquelocationque define su propia cabecera, típicamenteCache-Controlpara imágenes o el bloque de caché de Rocket-Nginx, pierde todas las cabeceras de seguridad. Guarda las líneas en un archivo e inclúyelo en el bloqueservery en cada uno de esos bloqueslocation. - Bloque server de HTTPS. Las líneas de nginx van en el bloque que sirve el puerto 443. Un bloque que solo redirige de HTTP a HTTPS no las necesita.
- Probar antes de recargar.
nginx -tcomprueba la sintaxis; recarga solo cuando indique éxito. IfModuleen Apache. Si faltamod_headers, Apache se salta el bloque en lugar de responder a cada petición con un error 500. La comprobación muestra entonces las cabeceras como ausentes, y el proveedor tiene que activar el módulo.- HSTS en Apache. La condición
expr=%{HTTPS} == 'on'limita HSTS a HTTPS, así que las mismas líneas funcionan en un.htaccessque sirve ambos protocolos. - Desactivar después «Enviar cabeceras de seguridad». Si no, WordPress añade cada cabecera por segunda vez a las páginas que genera.
El archivo de inclusión para nginx, como ejemplo:
# /etc/nginx/snippets/security-headers.conf holds the generated add_header lines
server {
listen 443 ssl;
server_name example.com;
include snippets/security-headers.conf;
location ~* \.(css|js|jpg|jpeg|png|webp|svg|woff2)$ {
add_header Cache-Control "public, max-age=2592000";
include snippets/security-headers.conf;
}
}
La comprobación de cabeceras
Comprobar las cabeceras de la página de inicio carga la página de inicio de tu sitio tres veces
desde el propio servidor: dos veces como un visitante, para que la segunda petición la responda una caché de páginas
si existe, y una vez con un parámetro adicional que evita la caché. Después compara lo que llega con tus ajustes.
Solo se solicita tu propia dirección; no se envía nada a reportedip.com. La comprobación cubre la página de inicio;
para otras páginas, archivos o la página de acceso usa la pestaña de red de las herramientas del navegador,
curl -sI https://example.com/ o la herramienta gratuita
Security Headers.
| Resultado | Significado | Qué hacer |
|---|---|---|
| Llega una vez, tal como se define aquí | La cabecera llega exactamente una vez con tu valor, en la página en caché y en la que no lo está. | Nada. |
| Falta en las páginas en caché | WordPress envía la cabecera, pero la caché de páginas entrega las páginas sin ella. | Activa la Protección ampliada. Si ya está activa, tu caché funciona sin PHP: usa la configuración del servidor web. |
| Falta en todas las páginas | Hive prevé la cabecera, pero no llega ni desde la caché ni sin ella. Algo entre WordPress y el visitante la elimina, como un proxy, un CDN o la configuración del hosting, o la página de inicio no viene de WordPress. | Define la cabecera en la configuración del servidor web y revisa el CDN o el proxy en busca de reglas que eliminen cabeceras de respuesta. |
| Enviada dos veces, por el servidor web y desde aquí | La misma cabecera llega más de una vez, normalmente porque el servidor web o el hosting la define y Hive también la envía. Los navegadores usan entonces uno de los valores o aplican ambos, lo que rara vez es lo deseado. | Mantén una sola fuente: quita la cabecera del servidor o desactívala aquí. Cuando todo esté en el servidor, desactiva Enviar cabeceras de seguridad. |
| Llega otro valor, lo define el servidor web o un plugin | Llega un valor, pero no el tuyo. El servidor web, el hosting, un CDN u otro plugin define la cabecera y se impone. | Encuentra la otra fuente y decide dónde vive la cabecera. Cambia o quita el valor allí. |
| Definida por el servidor web u otro plugin | Hive no prevé esta cabecera, porque está desactivada aquí o no forma parte de tu plan, pero llega. | Es lo esperado tras pasar las cabeceras al servidor web. Comprueba que el valor sea el que quieres. |
En lugar de la tabla pueden aparecer otros dos mensajes:
- «No llega ninguna cabecera de seguridad a la página de inicio, ni de WordPress ni del servidor web.» No hay nada definido en ningún sitio. Activa Enviar cabeceras de seguridad y guarda, o comprueba que la configuración del servidor esté activa.
- «No se pudo cargar la página de inicio» con un mensaje de error. El servidor no alcanza su propia dirección: una protección con contraseña en un sitio de pruebas, un cortafuegos del hosting que bloquea las peticiones del servidor a sí mismo o un dominio que apunta a otro lugar. Comprueba entonces las cabeceras desde fuera con las herramientas citadas arriba.
El registro de Estado del sistema muestra la sugerencia A las páginas en caché les faltan las cabeceras de seguridad cuando las cabeceras están activadas, hay una caché de páginas activa y la Protección ampliada no está en marcha. Desaparece en cuanto la Protección ampliada funciona. Si usas la configuración del servidor web y has desactivado Enviar cabeceras de seguridad, no aparece.
Solución de problemas
Una cabecera llega dos veces, aunque solo la definí en Hive
Entonces el hosting también la define. Los lugares habituales son las opciones de seguridad o SSL del panel de hosting (un interruptor de HSTS es frecuente), un .htaccess escrito por otro plugin o por el proveedor, el campo de directivas de nginx del panel y reglas del CDN que añaden cabeceras. Busca allí el nombre de la cabecera, mantén una sola fuente y vuelve a comprobar.
La comprobación muestra «Falta en las páginas en caché» aunque la Protección ampliada está activa
Tu caché de páginas entrega los archivos sin PHP, por ejemplo Rocket-Nginx, reglas de reescritura estáticas o una caché de servidor del hosting. Solo la configuración del servidor web llega a esas páginas. Con Rocket-Nginx incluye el archivo de cabeceras también en sus bloques location de caché, porque definen sus propias cabeceras.
Tras el cambio, las páginas en caché siguen mostrando valores antiguos
Según el plugin, una caché de páginas guarda las cabeceras junto con la página al crear el archivo de caché. Vacía la caché de páginas y la del CDN tras cada cambio de cabeceras y vuelve a comprobar.
¿Dónde van las líneas en un panel de hosting?
Las líneas de Apache van en el .htaccess del directorio de WordPress, encima del bloque de WordPress. Los paneles con nginx suelen ofrecer por dominio un campo para directivas adicionales de nginx (en Plesk en los ajustes de Apache y nginx, en ISPConfig en la pestaña Opciones); pega allí las líneas add_header. Algunos paneles colocan ese campo dentro de un bloque location, así que lanza la comprobación después. En un hosting compartido sin ninguna de las dos opciones, usa la Protección ampliada.
Han desaparecido los botones de pago, el mapa o el vídeo
Mira la consola del navegador. Una infracción de la CSP nombra el host bloqueado: añádelo a la directiva correspondiente. Un botón de Apple Pay o Google Pay ausente apunta a payment=() en la Permissions-Policy, un buscador de tiendas sin ubicación a geolocation=(). Si el contenido incrustado se rompe tras activar Cross-Origin-Embedder-Policy, la cabecera tiene que volver a desactivarse.
Un subdominio ya no es accesible
HSTS con includeSubDomains impone HTTPS en cada subdominio. Un subdominio sin certificado válido queda inaccesible para cada visitante que haya visto la cabecera, hasta que venza el max-age. Dale un certificado al subdominio y, si no es posible, desactiva includeSubDomains.
Faltan las cabeceras en wp-admin y en la página de acceso
Es lo previsto: WordPress y la Protección ampliada solo añaden las cabeceras a las páginas públicas. La configuración del servidor web cubre también wp-admin y la página de acceso.
Última actualización: · Mantenido por el equipo de ReportedIP