# Cabeceras de seguridad HTTP: qué son y cómo verificarlas

> Qué hacen HSTS, CSP, X-Frame-Options, nosniff, Referrer-Policy y Permissions-Policy, cómo añadirlas en Apache, Nginx, WordPress y PrestaShop y cómo verlas.

URL: https://webintacta.com/guias/cabeceras-de-seguridad-http
Última actualización: 2026-10-13

**En resumen:** Las cabeceras de seguridad HTTP que importan son seis: Strict-Transport-Security (HSTS), Content-Security-Policy (CSP), X-Frame-Options, X-Content-Type-Options (nosniff), Referrer-Policy y Permissions-Policy. Se añaden en Apache, Nginx, WordPress o PrestaShop y se comprueban con curl -I o con el análisis externo gratuito de WebIntacta. CSP conviene empezarla en modo observación (Report-Only) para no romper la web.


Por Jose Soriano (WebIntacta) · publicada el 2026-10-08

Las cabeceras de seguridad son unas pocas líneas que tu servidor envía con cada página y que le dicen al navegador qué puede hacer y qué no: usar solo HTTPS, no dejar que otra web te meta en un marco, no adivinar tipos de archivo. No sustituyen a tener la web actualizada, pero cierran ataques enteros a cambio de muy poco trabajo.

## Las seis que importan

### Strict-Transport-Security (HSTS)

Le dice al navegador que, durante el tiempo indicado, solo entre a tu web por HTTPS, aunque alguien escriba `http://` o pulse un enlace antiguo. Evita que un atacante en la misma red (una wifi pública) intercepte la primera visita sin cifrar.

```
Strict-Transport-Security: max-age=31536000; includeSubDomains
```

`max-age` va en segundos (31536000 es un año). `includeSubDomains` lo extiende a todos los subdominios: actívalo solo si **todos** funcionan con HTTPS, incluidos los internos. La directiva `preload` sirve para entrar en la lista que los navegadores traen de fábrica; para eso hacen falta al menos un año de `max-age`, `includeSubDomains`, redirección de HTTP a HTTPS y certificado válido en todos los subdominios. Salir de esa lista tarda meses, así que no la añadas por probar.

> Empieza con un max-age corto (por ejemplo 300 segundos), comprueba que todo va bien y súbelo después. Un HSTS largo con un subdominio sin HTTPS deja ese subdominio inaccesible para tus visitantes durante todo ese tiempo.

### Content-Security-Policy (CSP)

Es la que más protege y la más delicada. Define de qué orígenes puede cargar la página scripts, estilos, imágenes, fuentes o marcos. Si un atacante consigue inyectar un `<script>` que apunta a su dominio, una buena CSP impide que se ejecute. Es la defensa de fondo contra el XSS y contra muchos skimmers de tarjetas.

```
Content-Security-Policy: default-src 'self'; script-src 'self' https://www.googletagmanager.com; img-src 'self' data: https:; frame-ancestors 'self'; object-src 'none'; base-uri 'self'
```

El problema: un WordPress o un PrestaShop con diez plugins carga recursos de muchos sitios, y una CSP mal hecha rompe el pago, el chat o las analíticas. Más abajo explico cómo implantarla sin romper nada.

### X-Frame-Options y frame-ancestors

Impiden que otra web cargue la tuya dentro de un marco invisible para engañar al usuario y que haga clic donde no quiere (clickjacking). La forma moderna es la directiva `frame-ancestors` de la CSP; `X-Frame-Options` es la antigua, pero sigue siendo útil para navegadores viejos y no estorba tenerlas las dos. OWASP recomienda `frame-ancestors` si puedes, y si no, `X-Frame-Options: DENY`.

```
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
```

`DENY` prohíbe cualquier marco; `SAMEORIGIN` permite solo los de tu propio dominio (algunos editores visuales y constructores de páginas lo necesitan). Ojo: `frame-ancestors` no funciona si pones la CSP en una etiqueta `<meta>`; tiene que ir en la cabecera.

### X-Content-Type-Options

Con `nosniff`, el navegador respeta el tipo de archivo que declara el servidor y no intenta adivinarlo. Evita que un archivo subido como imagen se ejecute como script. No tiene contraindicaciones: ponla siempre.

```
X-Content-Type-Options: nosniff
```

### Referrer-Policy

Controla cuánta información de la página de origen se envía al pulsar un enlace hacia otra web. Con `strict-origin-when-cross-origin`, a otros dominios solo les llega tu dominio, no la URL completa (que puede llevar parámetros con datos de un pedido o de una búsqueda). Es el valor que recomienda OWASP y el que usan por defecto los navegadores actuales, pero conviene declararlo.

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

### Permissions-Policy

Desactiva funciones del navegador que tu web no usa: cámara, micrófono, geolocalización… Si un script inyectado intenta pedirlas, el navegador se niega. Unos paréntesis vacíos significan «nadie».

```
Permissions-Policy: camera=(), microphone=(), geolocation=()
```

Si tu tienda usa un método de pago que funciona con la API de pagos del navegador, o tu web tiene un mapa que pide la ubicación, no desactives esas funciones a ciegas: pruébalo.

### Las que sobran

`X-XSS-Protection` está obsoleta: OWASP recomienda no enviarla o ponerla a `0`, porque en navegadores antiguos podía crear fallos nuevos. Y conviene quitar `X-Powered-By` y las versiones de la cabecera `Server`, que solo le dicen al atacante qué software usas.

## Cómo añadirlas

### Apache (.htaccess)

En la mayoría de hostings compartidos con Apache, se añaden al `.htaccess` de la raíz. Necesita el módulo `mod_headers`, que casi todos tienen activo:

```
<IfModule mod_headers.c>
  Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
  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 Permissions-Policy "camera=(), microphone=(), geolocation=()"
  Header always unset X-Powered-By
</IfModule>
```

### Nginx

En el bloque `server` del sitio. El `always` hace que se envíen también en las páginas de error:

```
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
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 Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
```

> Trampa clásica de Nginx: si un bloque location tiene su propio add_header, deja de heredar los del bloque server. Las cabeceras desaparecen justo en esas rutas. Compruébalo en varias URL, no solo en la portada.

### WordPress

Lo mejor es ponerlas en el servidor (`.htaccess` o Nginx), porque así cubren también imágenes y archivos estáticos. Si no tienes acceso, puedes enviarlas desde PHP con el gancho `send_headers`, en un plugin propio o en un mu-plugin (no en el `functions.php` del tema, que se pierde si cambias de tema):

```
<?php
add_action( 'send_headers', function () {
    header( 'X-Content-Type-Options: nosniff' );
    header( 'Referrer-Policy: strict-origin-when-cross-origin' );
    header( 'Permissions-Policy: camera=(), microphone=(), geolocation=()' );
    header( 'X-Frame-Options: SAMEORIGIN' );
} );
```

Así solo se aplican a las páginas que genera WordPress, no a los archivos que sirve el servidor directamente. WordPress ya envía `X-Frame-Options: SAMEORIGIN` por su cuenta en la pantalla de acceso y en el escritorio.

### PrestaShop

PrestaShop regenera el `.htaccess` cuando guardas ciertos ajustes (URL amigables, por ejemplo). Conserva lo que esté **fuera** del bloque que delimitan sus comentarios `# ~~start~~` y `# ~~end~~`, así que pon tus cabeceras antes de `# ~~start~~` o después de `# ~~end~~`, nunca dentro. Si la tienda va en Nginx, en la configuración del servidor como arriba.

## CSP sin romper la web

La forma segura es empezar en modo observación con `Content-Security-Policy-Report-Only`. El navegador evalúa la política y avisa de lo que habría bloqueado, pero no bloquea nada:

```
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; img-src 'self' data: https:; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'
```

1. Publica la política en modo Report-Only.
2. Navega por la web con las herramientas de desarrollo abiertas (pestaña Consola): cada recurso que la política habría bloqueado aparece como aviso. Recorre sobre todo el carrito, el pago y los formularios.
3. Añade a la política los orígenes legítimos (pasarela de pago, analíticas, chat). Si quieres recibir los avisos de los visitantes reales, configura un destino con `report-to` (y `report-uri` para navegadores que aún no lo soportan).
4. Cuando pasen días sin avisos nuevos, cambia el nombre de la cabecera a `Content-Security-Policy`.

Report-Only no protege por sí sola: solo informa. No te quedes ahí indefinidamente. Y si la web depende de muchos scripts en línea, una CSP con `'unsafe-inline'` en `script-src` protege mucho menos; aun así, `frame-ancestors`, `object-src 'none'` y `base-uri 'self'` aportan desde el primer día.

## Cómo verificarlas

### En el navegador

Abre tu web, pulsa F12, ve a la pestaña **Red** (Network), recarga y haz clic en la primera petición (el documento). En **Encabezados de respuesta** verás todas las cabeceras que envía el servidor.

### Con curl

Desde la terminal de Windows, macOS o Linux:

```
curl -sI https://tu-web.com/
```

Por ejemplo, esta web responde (entre otras) con:

```
strict-transport-security: max-age=63072000; includeSubDomains; preload
content-security-policy: default-src 'self'; ... frame-ancestors 'none'; object-src 'none'; upgrade-insecure-requests
x-content-type-options: nosniff
x-frame-options: DENY
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=(), payment=(), usb=()
```

Comprueba también una página interior, una imagen y una URL que no exista: es donde suelen faltar.

> No copies a ciegas las cabeceras de otra web, tampoco las de este ejemplo. Una CSP con frame-ancestors 'none' impide que tu propio constructor de páginas cargue la web en su vista previa, y un Permissions-Policy con payment=() puede romper un botón de pago rápido. Cada línea tiene que tener sentido para tu web.

### Con el análisis gratuito

El [análisis gratuito](https://webintacta.com/analisis-seguridad-web-gratis) revisa las cabeceras de tu portada, la calidad de la CSP (si solo está en Report-Only, si permite scripts de cualquier sitio) y el HTTPS. Si necesitas que alguien las configure y compruebe que no rompen el pago, está incluido en el [mantenimiento de WordPress](https://webintacta.com/mantenimiento-wordpress) y en la revisión de [seguridad de WordPress](https://webintacta.com/seguridad-wordpress).

El mismo análisis lee también tu `robots.txt` y comprueba si publicas un `llms.txt`, el archivo que resume tu web para los asistentes de IA. Qué es, en qué se diferencia de `robots.txt` y cómo escribirlo, en la [guía de llms.txt](https://webintacta.com/guias/llms-txt).

## Fuentes

- [OWASP HTTP Headers Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html)
- [MDN: Content-Security-Policy-Report-Only](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy-Report-Only)
- [MDN: Strict-Transport-Security](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Strict-Transport-Security)
- [Requisitos de la lista HSTS preload](https://hstspreload.org/)
- [Nginx: directiva add_header](https://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header)

## Preguntas frecuentes

### ¿Qué son las cabeceras de seguridad HTTP?

Son líneas que el servidor envía con cada respuesta para indicar al navegador cómo comportarse: usar solo HTTPS, qué scripts puede cargar, si la página puede mostrarse dentro de un marco o qué funciones del navegador están permitidas.

### ¿Cómo veo las cabeceras de seguridad de una web?

En el navegador, con F12 → Red → la primera petición → Encabezados de respuesta. Desde la terminal, con curl -sI https://tu-web.com/. El análisis gratuito de WebIntacta también las revisa.

### ¿Puede una CSP romper mi web?

Sí, si bloquea un script que necesitas, como el de la pasarela de pago. Por eso se empieza con Content-Security-Policy-Report-Only, que solo avisa, y se pasa a la versión que bloquea cuando ya no aparecen avisos.

### ¿X-Frame-Options sigue siendo necesaria?

La directiva frame-ancestors de la CSP la sustituye en los navegadores actuales, pero X-Frame-Options sigue sirviendo para los antiguos y no estorba tener las dos.

### ¿Cómo añado cabeceras de seguridad en WordPress?

Lo mejor es hacerlo en el servidor, en el .htaccess (Apache) o en la configuración de Nginx. Si no tienes acceso, un pequeño plugin con el gancho send_headers puede enviarlas desde PHP.

## Sobre el autor

[Jose Soriano](https://webintacta.com/quien-soy): Desarrollador fullstack especializado en PrestaShop, WordPress y WooCommerce, con el curso y el examen oficiales de PrestaShop aprobados. Desarrolla tiendas online y módulos desde 2023 y es el fundador de WebIntacta, el servicio de seguridad web con el que analiza, limpia y mantiene él mismo webs de pymes y tiendas online, en remoto desde Ibi (Alicante). Datos de WebIntacta: https://webintacta.com/quien-soy#datos