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
| Header | Valor recomendado | Qué previene | Severity si falta |
|---|---|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains; preload | MITM / downgrade HTTPS | Medium |
Content-Security-Policy | default-src 'self'; frame-ancestors 'none'; ... | XSS, clickjacking, exfil | Medium-High |
X-Content-Type-Options | nosniff | MIME confusion XSS | Low |
X-Frame-Options | DENY o SAMEORIGIN | Clickjacking (legacy) | Low (si hay CSP frame-ancestors) |
Referrer-Policy | strict-origin-when-cross-origin | Token leak via Referer | Low-Medium |
Permissions-Policy | camera=(), microphone=(), geolocation=() | Abuse de APIs sensibles | Low |
Cross-Origin-Opener-Policy | same-origin | Spectre, window.opener | Low-Medium |
Cross-Origin-Embedder-Policy | require-corp | Spectre, side-channel | Low |
Cross-Origin-Resource-Policy | same-origin | Crossorigin leaks | Low |
Cache-Control (en endpoints auth) | no-store, private | Data leak via cache | Medium |
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)
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-pattern | Por 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.com | Si el CDN sirve user content (JSONP) → bypass instantáneo |
Sin frame-ancestors | Clickjacking |
Sin base-uri | <base> injection → cambia el origen de scripts relativos |
Sin form-action | Form 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ñadeCross-Origin-Opener-Policy: same-origin+ verificación dewindow.top === window.selfen JS crítico.
Test CSP
# 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
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
| Directiva | Significado |
|---|---|
max-age=31536000 | 1 año en segundos. Tiempo que el browser fuerza HTTPS |
includeSubDomains | Aplica a todos los subdomains. Crítico para evitar attacks via subdomain takeover http |
preload | Inscripció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
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=3600
| Flag | Qué hace | Cuándo es crítico |
|---|---|---|
Secure | Sólo en HTTPS | Siempre. Sin esto = leak via downgrade |
HttpOnly | Inaccesible desde JS | Sesiones, auth tokens — siempre |
SameSite=Lax | No se envía en cross-site POSTs | Default sensato. Protege CSRF en mutations |
SameSite=Strict | No se envía en NINGÚN cross-site request | Para tokens de máxima sensibilidad (banking) |
SameSite=None | Se envía en cross-site (necesita Secure) | Cookies de third-party widgets (analytics, embeds) |
__Host- prefix | Fuerza Secure, Path=/, sin Domain | Defense in depth para auth |
__Secure- prefix | Fuerza Secure | Para cookies de auth/session |
[!tip] SameSite Lax vs Strict en 2026 Chrome y Firefox ya hacen
SameSite=Laxpor 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
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.
| Valor | Cuándo |
|---|---|
no-referrer | Máxima privacidad. Para apps sensibles (medical, financial) |
strict-origin-when-cross-origin | Default sensato en 2026. Origin completo same-origin, sólo origin cross-origin, nada cross-origin http→https |
same-origin | Sólo same-origin envía referrer, cross-origin nada |
unsafe-url | NUNCA. 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.
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.
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 → cierrawindow.openerattacks. - COEP
require-corp: todos los recursos cargados deben tenerCross-Origin-Resource-Policyo 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-origines win gratuito para cerrar window.opener attacks. COEP rompe muchas apps third-party — implementar con cuidado.
Cómo testear todo de una
Herramientas
# 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
#!/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:
- No mandes 10 reports separados. Un report con tabla de headers faltantes + impacto agregado.
- Demuestra impacto real. "CSP permite
unsafe-inline" no es accionable. "CSP permiteunsafe-inlineY existe un reflected XSS en /search → bypass directo" → Medium. - Chain con otro bug. Header faltante + bug funcional = severity disparada.
- Bug bounty programs específicos. Algunos (Shopify, GitHub) explícitamente dicen "Missing security headers = N/A". Lee el scope.
Template de report headers
## 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 -sIal target → listar todos los response headers -
securityheaders.compara grade objetivo (A+ es target) - CSP en
csp-evaluator.withgoogle.com→ buscarunsafe-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-ancestorsen TODAS las pages - Permissions-Policy disabling APIs no usadas
- COOP
same-originmí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.
La checklist que repaso en cada objetivo nuevo
47 comprobaciones ordenadas por coste: primero lo que te puede meter en un lío, luego lo barato, y al final lo caro — que es donde están los bounties grandes. Te la mando al correo ahora mismo.
Te das de baja en un clic, desde cualquier correo.
Practica esto en un lab
Security Headers
Sigue aprendiendo · cuenta gratis
Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.
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.
7,99 €/mes · cancela cuando quieras
