Cada vez que un navegador pide una página, el servidor responde con el contenido y con una serie de cabeceras. Algunas de ellas le dicen al navegador qué puede y qué no puede hacer con esa página. Bien configuradas, cortan de raíz ataques muy comunes como el clickjacking, ciertas inyecciones de código o la degradación de HTTPS a HTTP.
Lo mejor: no requieren tocar la aplicación. Se configuran en el servidor web o en el proxy.
Cómo ver las cabeceras de tu web
Desde cualquier terminal Linux o macOS:
curl -sI https://tu-dominio.es
La opción -I pide solo las cabeceras y -s oculta la barra de progreso. Para filtrar las de seguridad:
curl -sI https://tu-dominio.es | grep -iE 'strict-transport|content-security|x-content-type|x-frame|referrer-policy|permissions-policy'
Si el comando no devuelve nada, tu web no envía ninguna.
Las seis cabeceras importantes
Strict-Transport-Security (HSTS)
Obliga al navegador a usar siempre HTTPS con tu dominio, incluso si alguien escribe http:// o sigue un enlace antiguo.
Strict-Transport-Security: max-age=31536000; includeSubDomains
Empieza con un
max-agebajo (por ejemplo,300) y súbelo cuando confirmes que todos tus subdominios funcionan con HTTPS. Una vez el navegador la recibe, no aceptará HTTP durante ese tiempo.
Content-Security-Policy (CSP)
Define de qué orígenes puede cargar la página scripts, estilos, imágenes o fuentes. Es la defensa más potente contra XSS, pero también la más delicada de configurar.
Content-Security-Policy: default-src 'self'; img-src 'self' data:; object-src 'none'; frame-ancestors 'none'
Para probarla sin romper nada, usa primero Content-Security-Policy-Report-Only: el navegador avisa en la consola de lo que bloquearía, pero no lo bloquea.
X-Content-Type-Options
Impide que el navegador “adivine” el tipo de un archivo y, por ejemplo, ejecute como script algo que se subió como imagen.
X-Content-Type-Options: nosniff
X-Frame-Options
Evita que otra web cargue la tuya dentro de un <iframe> para engañar al usuario (clickjacking). La directiva moderna equivalente es frame-ancestors dentro de la CSP; enviar ambas cubre navegadores antiguos.
X-Frame-Options: DENY
Referrer-Policy
Controla cuánta información de la URL de origen se envía al navegar a otro sitio. Evita filtrar rutas internas o parámetros.
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy
Desactiva funciones del navegador que tu web no usa: cámara, micrófono, geolocalización…
Permissions-Policy: camera=(), microphone=(), geolocation=()
Ejemplo con Caddy
Si usas Caddy como servidor web o proxy inverso, todas se añaden en un bloque:
tu-dominio.es {
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
Content-Security-Policy "default-src 'self'; img-src 'self' data:; object-src 'none'; frame-ancestors 'none'"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
Permissions-Policy "camera=(), microphone=(), geolocation=()"
-Server
}
root * /srv/web
file_server
}
La línea -Server elimina la cabecera que anuncia qué software usa el servidor: un dato menos para quien busca versiones vulnerables.
Checklist rápido
| Cabecera | Valor recomendado de partida |
|---|---|
| Strict-Transport-Security | max-age=31536000; includeSubDomains |
| Content-Security-Policy | Empezar en modo Report-Only |
| X-Content-Type-Options | nosniff |
| X-Frame-Options | DENY |
| Referrer-Policy | strict-origin-when-cross-origin |
| Permissions-Policy | Desactivar lo que no se use |
Las cabeceras no sustituyen a mantener el software actualizado, pero son una de las mejoras con mejor relación esfuerzo/resultado que puede hacer cualquier web.