Ingeniería

Cabeceras de seguridad HTTP: función real de cada directiva

Seis cabeceras que neutralizan categorías enteras de ataques: qué hace cada una, qué errores evitar y las dos directivas obsoletas que debe eliminar.

Las cabeceras de seguridad HTTP representan la forma más económica y eficaz de fortalecer la infraestructura de un sitio web. Cada una consiste en una línea de configuración en el servidor, no penalizan el rendimiento y, combinadas, neutralizan familias enteras de vulnerabilidades web.

La mayoría de sitios web no envían ninguna de ellas.

A continuación, explicamos la función de cada cabecera por orden de prioridad técnica y señalamos las dos directivas obsoletas que conviene eliminar de inmediato.

Inicio prioritario: las tres cabeceras seguras sin riesgo de incompatibilidad

Estas tres directivas pueden desplegarse hoy mismo en cualquier entorno sin riesgo de alterar el funcionamiento del sitio.

1. X-Content-Type-Options: nosniff

X-Content-Type-Options: nosniff

Un único valor, sin configuración adicional y sin contraindicaciones técnicas.

Sin esta cabecera, los navegadores intentan deducir (sniffing) el tipo MIME de los archivos si consideran que difiere del declarado por el servidor. Esta conducta permite ataques donde un archivo subido por un usuario —declarado formalmente como imagen— se ejecuta como código JavaScript porque su contenido interno incluye scripts maliciosos.

No existe motivo legítimo para omitir esta cabecera. Si su servidor no la emite, es la primera corrección que debe aplicar.

2. X-Frame-Options

X-Frame-Options: SAMEORIGIN

Impide que sus páginas sean incrustadas dentro de marcos <iframe> en sitios de terceros. Así es exactamente como operan los ataques de clickjacking: una web maliciosa carga su interfaz en un marco transparente superpuesto a un botón señuelo, logrando que el usuario interactúe con su aplicación sin advertirlo.

SAMEORIGIN autoriza que su propio dominio pueda incrustar sus páginas, que es la configuración habitual requerida. DENY bloquea cualquier incrustación externa o interna.

Su equivalente moderno es la directiva frame-ancestors dentro de CSP. Mantener ambas directivas asegura compatibilidad plena con navegadores antiguos sin coste alguno.

3. Referrer-Policy

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

Determina qué información de la URL de origen se transmite al hacer clic en un enlace que apunta a un servidor externo.

Sin esta política, se envía la URL completa con todos sus parámetros de consulta (query strings). Tokens de restablecimiento de contraseña, identificadores de sesión, términos de búsqueda interna e identificadores de clientes se han filtrado históricamente por esta vía hacia servicios de terceros.

strict-origin-when-cross-origin envía la URL completa en navegación interna, únicamente el dominio de origen (sin rutas ni parámetros) hacia otros sitios HTTPS y ningún dato si la conexión se degrada a HTTP inseguro.

Segunda fase: HSTS (Strict-Transport-Security)

Strict-Transport-Security: max-age=31536000; includeSubDomains

Instruye al navegador para que se comunique con su dominio exclusivamente mediante HTTPS durante el periodo estipulado, sin intentar siquiera una conexión previa por HTTP.

Aporta dos beneficios clave. A nivel de seguridad, erradica la ventana de vulnerabilidad donde una petición HTTP inicial podría ser interceptada antes de ejecutarse la redirección 301. A nivel de rendimiento, elimina por completo la redirección http→https para usuarios recurrentes, ahorrando un viaje de red completo en cada carga.

Protocolo de despliegue gradual: HSTS es un compromiso estricto que los navegadores aplican de forma irreversible durante el tiempo configurado. Si establece un max-age de un año con includeSubDomains y posteriormente detecta un subdominio interno que solo admite HTTP, dicho subdominio quedará inaccesible para todos sus visitantes durante meses.

Procedimiento seguro:

  1. Confirmar que todos los subdominios disponen de certificados HTTPS válidos.
  2. Desplegar con max-age=300 durante varios días de prueba.
  3. Incrementar a max-age=86400 durante una semana.
  4. Establecer finalmente max-age=31536000; includeSubDomains.

La directiva preload incluye su dominio en la lista fija compilada dentro de los navegadores. Su retirada es un proceso complejo que demora meses: actívela únicamente tras verificar la estabilidad total de su infraestructura.

La directiva principal: Content-Security-Policy (CSP)

CSP define qué orígenes tienen autorización para cargar scripts, estilos, imágenes, fuentes tipográficas y conexiones de red en la página. Bien configurada, mitiga la inmensa mayoría de ataques de Cross-Site Scripting (XSS) incluso si la inyección de código tiene éxito, ya que el navegador deniega la ejecución de scripts procedentes de fuentes no autorizadas.

Es también la única cabecera de esta lista que puede interrumpir funciones del sitio si se define de forma incorrecta.

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self'

El compromiso de unsafe-inline: la mayoría de sitios web utilizan fragmentos de código <script> en línea (etiquetas analíticas, píxeles de seguimiento, utilidades). Una política CSP estricta los bloquea por defecto. Añadir 'unsafe-inline' a script-src evita errores de consola pero reduce notablemente la protección, pues los scripts en línea son precisamente el vector de ataque principal.

La solución técnica rigurosa son los valores nonce o hashes: generar un valor aleatorio criptográfico por petición en el servidor, asociarlo a los scripts legítimos y declararlo en la cabecera CSP.

Despliegue inicial en modo solo reporte:

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

En este modo ningún recurso es bloqueado; las infracciones se envían al endpoint de registro. Manténgalo durante dos a cuatro semanas, autorice los servicios legítimos detectados y active la cabecera definitiva.

Cuatro directivas de alta seguridad y bajo riesgo para cualquier política: frame-ancestors (previene clickjacking), base-uri 'self' (evita manipulaciones de rutas relativas mediante etiquetas <base>), form-action 'self' (bloquea el envío de formularios a destinos externos no autorizados) y object-src 'none' (inhabilita plugins obsoletos tipo Flash).

Permissions-Policy

Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=()

Declara qué APIs del navegador tiene permitido utilizar el documento web. Denegar explícitamente funcionalidades no utilizadas limita las capacidades de scripts de terceros que pudieran verse comprometidos. Si su web nunca solicita acceso a la cámara o micrófono, declararlo formalmente no cuesta nada y elimina ese vector en todos los scripts de la página.

Dos cabeceras que debe eliminar

X-XSS-Protection es obsoleta. Activaba un filtro de protección XSS en el navegador que fue retirado de Chromium y Firefox debido a que el propio filtro introducía nuevas vulnerabilidades explotables. Su presencia solo denota configuraciones heredadas sin revisar.

Server y X-Powered-By con números de versión detallan con exactitud el software y versión del servidor. Cuando se publica una vulnerabilidad, los atacantes realizan escaneos masivos buscando exactamente estos encabezados. Suprímalos en su configuración:

Header unset X-Powered-By
Header unset Server
ServerTokens Prod

Configuración en Apache / LiteSpeed

Para entornos con servidor web Apache o LiteSpeed (mediante .htaccess):

<IfModule mod_headers.c>
  Header always set X-Content-Type-Options "nosniff"
  Header always set X-Frame-Options "SAMEORIGIN"
  Header always set Referrer-Policy "strict-origin-when-cross-origin"
  Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
  Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS
  Header unset X-Powered-By
</IfModule>

El parámetro always es fundamental: garantiza que las cabeceras se emitan también en las respuestas de error (4xx y 5xx), que es cuando más se necesita proteger la aplicación. En Nginx, la directiva equivalente es add_header … always;.

Auditoría y verificación

Puede inspeccionar las cabeceras emitidas por cualquier dominio en tiempo real con nuestro escáner gratuito de cabeceras de seguridad. Analiza la respuesta del servidor, evalúa los valores implementados y señala las configuraciones débiles con sus motivos técnicos específicos.

Secuencia de implementación recomendada

  1. X-Content-Type-Options — implementación inmediata sin riesgo
  2. X-Frame-Options — implementación inmediata sin riesgo
  3. Referrer-Policy — implementación inmediata sin riesgo
  4. Eliminar X-XSS-Protection y cabeceras de versión del servidor
  5. Permissions-Policy — restringir APIs no utilizadas
  6. Strict-Transport-Security (HSTS) — despliegue por fases
  7. Content-Security-Policy — auditoría en modo reporte y posterior activación

Los pasos 1 al 5 se ejecutan en un único despliegue técnico. Los pasos 6 y 7 requieren una supervisión planificada. Aplicar únicamente los cinco primeros puntos ya sitúa a su sitio web por encima de la media de seguridad técnica de internet.

Seguir leyendo

Cuéntenos qué objetivo busca alcanzar.

Un equipo. Tres oficinas. Veintiséis idiomas. Plantéenos su problema y recibirá una respuesta técnica de nivel senior — no un guion comercial.

Una propuesta detallada en un día laborable, en su idioma.