Checklist de cabeceras de seguridad HTTP (con configuraciones para copiar y pegar)
Unas pocas cabeceras de respuesta bloquean clases enteras de ataques (clickjacking, MIME sniffing, degradación a HTTP, gran parte del XSS) con un coste casi nulo. Aquí tienes las cabeceras que merece la pena enviar, valores iniciales seguros y cómo desplegar la más delicada (CSP) sin romper tu sitio.
El checklist
| Cabecera | Valor seguro | Protege contra |
|---|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains | Degradación a HTTP y robo de cookies en Wi-Fi público |
Content-Security-Policy | Empieza en modo solo informe (abajo) | XSS, scripts inyectados, exfiltración de datos |
X-Content-Type-Options | nosniff | Navegadores que ejecutan subidas como scripts |
CSP frame-ancestors | 'self' (o X-Frame-Options: SAMEORIGIN) | Clickjacking |
Referrer-Policy | strict-origin-when-cross-origin | Filtración de URLs completas (tokens, IDs) a otros sitios |
Permissions-Policy | camera=(), microphone=(), geolocation=() | Scripts de terceros usando funciones del dispositivo |
Comprueba cuáles de estas cabeceras envía ahora tu sitio, con una nota, en el Security Headers Checker.
HSTS: empieza con un valor corto
Una vez que un navegador ve HSTS, rechaza HTTP plano durante todo el max-age. Asegúrate primero de que cada subdominio funciona por HTTPS (revisa los certificados con el SSL Checker), empieza con max-age=300 y luego súbelo a un año. Añade preload y envía el dominio a la lista de precarga de HSTS solo cuando estés seguro: quitarlo tarda meses.
Content-Security-Policy sin romper nada
CSP indica de dónde pueden cargarse scripts, estilos, imágenes y conexiones. Despliégalo en modo solo informe, que registra las infracciones sin bloquear nada:
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' https://www.googletagmanager.com; img-src 'self' data: https:; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'; report-uri /csp-report
Vigila la consola del navegador y tu endpoint de informes durante una semana, añade los orígenes que realmente usas y después cambia el nombre de la cabecera a Content-Security-Policy. Evita 'unsafe-inline' para scripts; usa nonces o hashes para los scripts en línea que controles. Construye la política origen por origen con el CSP Generator.
Configuraciones
Nginx (dentro de server; always mantiene las cabeceras 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 Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "frame-ancestors 'self'" always;
Apache (.htaccess, con mod_headers):
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Vercel (vercel.json):
{ "headers": [ { "source": "/(.*)", "headers": [
{ "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains" },
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" }
] } ] }
Genera configuraciones completas del servidor con el Nginx Config Generator o el .htaccess Generator.
Cabeceras que puedes eliminar
X-XSS-Protection está obsoleta: los navegadores modernos eliminaron el filtro que controlaba, y 0 es el valor recomendado si aún la envías. Expect-CT está en desuso. Ocultar Server y X-Powered-By es buena higiene, pero no es una protección real.