Nuevos labs cada semana — Accede a todos desde 5€/mes

Nivel BásicoGratis

Security headers checklist 2026 — CSP, HSTS, X-Frame, Referrer-Policy y más

Audit completo de HTTP security headers que cualquier aplicación moderna debe tener: ejemplos reales, configuración correcta, errores comunes y cómo reportarlos.

Gorka El Bochi11 de mayo de 202611 min

Respuesta rápida

Security headers son la primera línea de defensa contra XSS, clickjacking, MITM y info leaks. Audit mínimo en 2026: CSP (con frame-ancestors + sin unsafe-inline), HSTS (preload + includeSubDomains), X-Content-Type-Options nosniff, Referrer-Policy strict-origin-when-cross-origin, Cookies Secure + HttpOnly + SameSite=Lax, Permissions-Policy explícita. Reports de headers solos suelen ser info/low (€50-€200), pero como chain con otro bug pueden disparar la severity 2 niveles.


Tabla completa — headers que mirar

HeaderValor recomendadoQué previeneSeverity si falta
Strict-Transport-Securitymax-age=31536000; includeSubDomains; preloadMITM / downgrade HTTPSMedium
Content-Security-Policydefault-src 'self'; frame-ancestors 'none'; ...XSS, clickjacking, exfilMedium-High
X-Content-Type-OptionsnosniffMIME confusion XSSLow
X-Frame-OptionsDENY o SAMEORIGINClickjacking (legacy)Low (si hay CSP frame-ancestors)
Referrer-Policystrict-origin-when-cross-originToken leak via RefererLow-Medium
Permissions-Policycamera=(), microphone=(), geolocation=()Abuse de APIs sensiblesLow
Cross-Origin-Opener-Policysame-originSpectre, window.openerLow-Medium
Cross-Origin-Embedder-Policyrequire-corpSpectre, side-channelLow
Cross-Origin-Resource-Policysame-originCrossorigin leaksLow
Cache-Control (en endpoints auth)no-store, privateData leak via cacheMedium

Content-Security-Policy — el header rey

CSP es el más complejo y el más impactante. Una CSP mal hecha pasa todos los XSS; una CSP bien hecha bloquea incluso XSS reflejados.

Ejemplo de CSP correcta (SPA moderna)

css
Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-RANDOM123' https://js.stripe.com;
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  font-src 'self' data:;
  connect-src 'self' https://api.target.com wss://ws.target.com;
  frame-src https://js.stripe.com https://hooks.stripe.com;
  frame-ancestors 'none';
  form-action 'self';
  base-uri 'self';
  object-src 'none';
  upgrade-insecure-requests;
  report-uri /csp-report

Errores que matan la CSP

Anti-patternPor qué es malo
script-src 'unsafe-inline'Permite inline <script> → cualquier XSS reflejado pasa
script-src 'unsafe-eval'eval(), Function(), setTimeout(string) → gadget chains
script-src https:Permite scripts de cualquier HTTPS → no protege nada
script-src *.cdn.comSi el CDN sirve user content (JSONP) → bypass instantáneo
Sin frame-ancestorsClickjacking
Sin base-uri<base> injection → cambia el origen de scripts relativos
Sin form-actionForm hijacking en XSS to exfil credentials
default-src 'self' sin object-src 'none'<object data="data:..."> ejecuta Flash legacy

[!danger] frame-ancestors NO es suficiente frame-ancestors 'none' previene iframing tradicional, pero no previene window.open() popups con clickjacking via UI confusion. Para cerrar el vector completo: añade Cross-Origin-Opener-Policy: same-origin + verificación de window.top === window.self en JS crítico.

Test CSP

bash
# Ver el header
curl -sI https://target.com | grep -i content-security

# Evaluator oficial Google
# Pega la CSP en https://csp-evaluator.withgoogle.com/

# Buscar bypasses según las whitelisted domains
# https://github.com/PortSwigger/csp-bypass

HSTS — el header simple pero crítico

ini
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
DirectivaSignificado
max-age=315360001 año en segundos. Tiempo que el browser fuerza HTTPS
includeSubDomainsAplica a todos los subdomains. Crítico para evitar attacks via subdomain takeover http
preloadInscripción en la HSTS preload list de Chrome/Firefox (hardcoded)

Preload list

Inscríbete en hstspreload.org. Requisitos:

  • Servir HSTS con max-age >= 31536000, includeSubDomains, preload.
  • Redirect HTTP → HTTPS en root + en todos los subdomains.
  • Soportar HTTPS en todos los subdomains (incluso mail.target.com).

Cookies — los flags que cuentan

ini
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=3600
FlagQué haceCuándo es crítico
SecureSólo en HTTPSSiempre. Sin esto = leak via downgrade
HttpOnlyInaccesible desde JSSesiones, auth tokens — siempre
SameSite=LaxNo se envía en cross-site POSTsDefault sensato. Protege CSRF en mutations
SameSite=StrictNo se envía en NINGÚN cross-site requestPara tokens de máxima sensibilidad (banking)
SameSite=NoneSe envía en cross-site (necesita Secure)Cookies de third-party widgets (analytics, embeds)
__Host- prefixFuerza Secure, Path=/, sin DomainDefense in depth para auth
__Secure- prefixFuerza SecurePara cookies de auth/session

[!tip] SameSite Lax vs Strict en 2026 Chrome y Firefox ya hacen SameSite=Lax por default si no se especifica. Pero todavía hay endpoints en frameworks viejos que setean sin SameSite explícito → reportable. Strict rompe flows de OAuth/SSO porque la cookie no llega tras redirect → Lax es el sweet spot.


Referrer-Policy — el leak silencioso

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

Sin esta header, el browser envía el Referer completo (incluyendo path + query) a cualquier sitio externo al que linkees. Resultado: tokens de password reset, session IDs en query, OAuth codes — todos filtrados a third-parties.

ValorCuándo
no-referrerMáxima privacidad. Para apps sensibles (medical, financial)
strict-origin-when-cross-originDefault sensato en 2026. Origin completo same-origin, sólo origin cross-origin, nada cross-origin http→https
same-originSólo same-origin envía referrer, cross-origin nada
unsafe-urlNUNCA. Envía URL completa siempre

Reportable

URLs con tokens en query (?reset_token=, ?session=, ?code=) + sin Referrer-Policy restrictiva → al user hacer click en link externo, token se filtra al third-party. Severity Medium si el token sigue siendo válido.


Permissions-Policy — el moderno (ex Feature-Policy)

Antes era Feature-Policy. Renamed a Permissions-Policy en 2020+ y soporta más APIs.

ini
Permissions-Policy:
  camera=(),
  microphone=(),
  geolocation=(),
  payment=(self),
  usb=(),
  accelerometer=(),
  gyroscope=(),
  magnetometer=(),
  interest-cohort=()
  • camera=() → ningún origen puede acceder.
  • camera=(self) → sólo same-origin.
  • camera=(self "https://trusted.com") → same-origin + ese específico.
  • interest-cohort=() → opt-out de FLoC/Topics API tracking.

Reportable si la app embedded en iframe puede activar mic/camera/geolocation sin que el usuario lo espere → defense in depth.


COEP / COOP / CORP — cross-origin isolation

Necesarios para usar SharedArrayBuffer, performance.now() de alta precisión, y mitigar Spectre/Meltdown.

makefile
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin
  • COOP same-origin: tu window no comparte browsing context con popups cross-origin → cierra window.opener attacks.
  • COEP require-corp: todos los recursos cargados deben tener Cross-Origin-Resource-Policy o CORS. Activa "cross-origin isolation".
  • CORP same-origin: tus recursos sólo pueden ser cargados desde same-origin.

[!info] Cuándo activarlos Si tu app usa SharedArrayBuffer (WebAssembly, threading), necesitas COOP+COEP. Si tu app NO los usa, COOP same-origin es win gratuito para cerrar window.opener attacks. COEP rompe muchas apps third-party — implementar con cuidado.


Cómo testear todo de una

Herramientas

bash
# CLI rápido
curl -sI https://target.com

# Online — el estándar de facto
# https://securityheaders.com/?q=target.com
# https://observatory.mozilla.org/analyze/target.com

# CSP específico
# https://csp-evaluator.withgoogle.com/

Script manual de audit

bash
#!/bin/bash
URL="$1"

echo "=== Headers de $URL ==="
curl -sI "$URL" | grep -iE "(strict-transport|content-security|x-content-type|x-frame|referrer-policy|permissions-policy|cross-origin|set-cookie)"

echo -e "\n=== Cookies analysis ==="
curl -sI "$URL" | grep -i "set-cookie:" | while read -r line; do
    name=$(echo "$line" | sed 's/.*Set-Cookie: \([^=]*\)=.*/\1/i')
    flags=""
    echo "$line" | grep -qi "HttpOnly" || flags+="[NO HttpOnly] "
    echo "$line" | grep -qi "Secure" || flags+="[NO Secure] "
    echo "$line" | grep -qi "SameSite" || flags+="[NO SameSite] "
    [ -n "$flags" ] && echo "Cookie '$name': $flags"
done

Cómo reportarlo (sin ser low-info spam)

Headers sueltos casi siempre son info / low. Para que el report tenga valor:

  1. No mandes 10 reports separados. Un report con tabla de headers faltantes + impacto agregado.
  2. Demuestra impacto real. "CSP permite unsafe-inline" no es accionable. "CSP permite unsafe-inline Y existe un reflected XSS en /search → bypass directo" → Medium.
  3. Chain con otro bug. Header faltante + bug funcional = severity disparada.
  4. Bug bounty programs específicos. Algunos (Shopify, GitHub) explícitamente dicen "Missing security headers = N/A". Lee el scope.

Template de report headers

markdown
## Summary
La aplicación carece de las siguientes security headers, exponiendo a usuarios a clickjacking, XSS amplificado y leak de tokens via Referer.

## Headers afectados
| Header | Esperado | Actual |
|---|---|---|
| CSP | `default-src 'self'; frame-ancestors 'none'` | Ausente |
| HSTS | `max-age=31536000; includeSubDomains` | `max-age=300` |
| X-Frame-Options | `DENY` | Ausente |

## Impact
- Sin CSP: cualquier XSS reflejado/stored ejecuta sin restricción.
- HSTS débil: ventana de 5 min para MITM downgrade.
- Sin X-Frame-Options: clickjacking en /transfer endpoint posible.

## PoC clickjacking
[HTML con iframe del /transfer endpoint + overlay malicioso]

Hunting checklist

  • curl -sI al target → listar todos los response headers
  • securityheaders.com para grade objetivo (A+ es target)
  • CSP en csp-evaluator.withgoogle.com → buscar unsafe-inline, unsafe-eval, * whitelisted
  • HSTS: max-age >= 31536000 + includeSubDomains + preload
  • Cookies de auth: Secure + HttpOnly + SameSite=Lax|Strict
  • Referrer-Policy presente y restrictiva
  • X-Frame-Options o CSP frame-ancestors en TODAS las pages
  • Permissions-Policy disabling APIs no usadas
  • COOP same-origin mínimo en pages auth-críticas
  • Cache-Control en endpoints autenticados: no-store, private
  • Probar chain con XSS/CSRF/clickjacking para subir severity

Labs relacionados

Practica explotación de aplicaciones con headers mal configurados y chains de XSS → CSP bypass en labs de Security Headers.

Practica esto en un lab

Security Headers

Resolver

Sigue aprendiendo · cuenta gratis

Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.

Crear cuenta
Premium · 1 técnica más

Hay un payload extra al final

Por qué `frame-ancestors 'none'` en CSP NO es suficiente para prevenir clickjacking en 2026, y la regla CSP que sí cierra todos los vectores.

Desbloquear

5 €/mes · cancela cuando quieras

Artículos relacionados