Defaults.Exposed

Defaults.ExposedSoluciones › Protección contra adivinación de tipos MIME (X-Content-Type-Options)

Cómo arreglar Protección contra adivinación de tipos MIME (X-Content-Type-Options)

Una cabecera de una sola línea que impide a los navegadores adivinar qué es realmente un archivo. Sin ella, un archivo que alguien suba a tu sitio (o un archivo de tus propias páginas) puede ser malinterpretado por el navegador y ejecutarse como código, que es exactamente como algunos ataques convierten una subida de aspecto inofensivo en una vía para robar las sesiones de tus clientes.

En resumen, para tu negocio: Que falte esta cabecera es una señal clara y detectable de que lo básico no está en su sitio. Por sí sola rara vez tumba un sitio, pero combinada con un formulario de subida de archivos o contenido generado por usuarios abre una vía para que un atacante ejecute código malicioso en los navegadores de tus visitantes: secuestrar sesiones iniciadas, robar datos de tarjeta o de inicio de sesión y dejarte en el lado equivocado de una conversación sobre una brecha de datos. Es una de las soluciones más baratas en seguridad: una línea, gratis, unos cinco minutos.

Lo que esto te puede costar

Por qué importa. Cuando un servidor es vago sobre qué es un archivo, los navegadores intentan adivinarlo («olfatearlo»). Los atacantes aprovechan esa adivinación: suben un archivo que el servidor etiqueta como imagen, pero crean su contenido de forma que el navegador decida que en realidad es JavaScript, y lo ejecute. La cabecera X-Content-Type-Options: nosniff indica a todos los navegadores que dejen de adivinar y confíen en el tipo declarado por el servidor, cerrando toda esa categoría de truco. Es una comprobación puntuada que vale 25 puntos y se califica de severidad media cuando falta.

La versión corta para el dueño

Hay una suposición silenciosa metida en cada navegador web: cuando descarga un archivo de tu sitio, intenta averiguar qué tipo de archivo es. Normalmente confía en tu servidor. Pero si tu servidor es vago, el navegador adivinará, y esa adivinación se llama olfateo de tipos MIME.

El problema es que los atacantes pueden manipular la adivinación. Pueden crear un archivo que tu servidor crea de verdad que es una imagen inofensiva, pero que el navegador, al dejarlo adivinar, decida que en realidad es un trozo de código de programa, y entonces lo ejecute, justo dentro del navegador de tu cliente, en tu dominio.

Existe una instrucción de una sola línea que apaga la adivinación: X-Content-Type-Options: nosniff. Le dice a todos los navegadores: «no adivines, confía exactamente en lo que mi servidor te dice». Esa es toda la solución. Es gratis, lleva unos cinco minutos y, en un sitio bien construido, no rompe nada.

Esta comprobación busca esa cabecera. Si falta, pierdes 25 puntos y se califica como un problema de severidad media, no porque la cabecera por sí sola sea una catástrofe, sino porque su ausencia es una señal fiable de que lo básico no se ha asegurado.

Lo que esto puede costarte

Estos son escenarios realistas, a nivel de negocio, no teatro del peor caso.

Ninguno de estos casos requiere un atacante sofisticado. El abuso del olfateo MIME es bien conocido y está automatizado, que es exactamente por qué los analizadores marcan con tanta firmeza la cabecera ausente.

Qué es en realidad

Cuando un navegador recibe un archivo, se supone que el servidor lo etiqueta con un tipo de contenido (por ejemplo, image/png para una imagen PNG o text/html para una página web). Históricamente, los navegadores no confiaban del todo en esa etiqueta —en parte porque algunos servidores la ponían mal—, así que echaban un vistazo a los bytes reales del archivo y decidían por su cuenta. Ese vistazo es el olfateo de tipos MIME.

Era una comodidad que se convirtió en un riesgo. Si un atacante consigue meter un archivo en tu sitio (a través de un formulario de subida, un campo de comentarios, un documento importado) e influir en su contenido, puede crear algo que el servidor etiquete de forma inocua pero que el navegador olfatee como script ejecutable. El navegador entonces lo ejecuta en tu dominio, con toda la confianza que tu dominio acarrea.

X-Content-Type-Options: nosniff elimina la adivinación por completo. Con ella puesta, al navegador se le dice: usa el tipo declarado por el servidor y nada más. Un archivo etiquetado como imagen se trata como imagen, punto, aunque su contenido parezca un script. El vector de ataque se cierra.

Cómo es lo «bueno»: cada respuesta de tu sitio —páginas y recursos por igual— lleva exactamente esta cabecera:

X-Content-Type-Options: nosniff

No hay otro valor válido ni nada que ajustar. Si tu CDN y tu servidor la añaden los dos (de modo que ves nosniff, nosniff), no pasa nada y sigue contando como aprobado.

Cómo solucionarlo (gratis, ~5 minutos)

Pásale este apartado a quien lleve tu sitio web: tu informático, tu desarrollador web o el soporte de tu hosting. La solución es gratuita y rápida; no hay nada que comprar. Lo que pides es simple: «Añade la cabecera de respuesta X-Content-Type-Options: nosniff a todas las páginas y recursos del sitio.»

Aquí va el detalle para ellos, por plataforma común.

Cloudflare (o un CDN/proxy similar) — a menudo el sitio más rápido para hacerlo, cubriendo todo el sitio a la vez:

Nginx — añade dentro del bloque server (o location) correspondiente:

add_header X-Content-Type-Options "nosniff" always;

La palabra clave always garantiza que también se envíe en las respuestas de error. Recarga Nginx tras guardar.

Apache — requiere mod_headers habilitado; en la configuración del sitio o en .htaccess:

Header always set X-Content-Type-Options "nosniff"

IIS / hosting Windows — en web.config, bajo <system.webServer>:

<httpProtocol>
  <customHeaders>
    <add name="X-Content-Type-Options" value="nosniff" />
  </customHeaders>
</httpProtocol>

Node / Express — establécela en cada respuesta:

app.use((req, res, next) => {
  res.setHeader('X-Content-Type-Options', 'nosniff');
  next();
});

(O usa el paquete helmet, que establece esta y otras varias cabeceras de seguridad por defecto.)

Sitios en Google Workspace / Microsoft 365: estos gestionan tu correo y tus documentos, no el hosting de tu sitio web público, así que la cabecera no se pone ahí; se pone donde se sirva tu sitio (tu CDN, servidor web o constructor de sitios). Si usas un constructor de sitios alojado (Squarespace, Wix, Shopify y similares), muchos añaden esta cabecera por ti automáticamente; comprueba el resultado en lugar de suponerlo, y pregunta a su soporte si falta.

Tras el despliegue, verifícalo. Vuelve a ejecutar tu análisis, o pide a tu desarrollador que compruebe las cabeceras de respuesta en las herramientas de desarrollo del navegador (pestaña Red → clic en cualquier petición → Cabeceras de respuesta) y confirme que X-Content-Type-Options: nosniff está presente. Prueba el sitio brevemente para confirmar que nada con estilo o script se rompió; en un sitio bien construido, no se romperá nada.

Errores habituales

Pásaselo a tu informático

El resumen técnico: esta comprobación inspecciona las cabeceras de respuesta HTTP y pasa cuando X-Content-Type-Options está presente y su valor (sin distinguir mayúsculas) contiene nosniff, incluido el caso multifuente nosniff, nosniff donde un CDN y el origen la ponen los dos. Que falte o cualquier valor distinto de nosniff no pasa. Es una comprobación puntuada P2 que vale 25 puntos, calificada de severidad media cuando falla, y se corresponde con OWASP Top 10 A05 (Configuración de seguridad incorrecta). La remediación es una sola cabecera de respuesta estática aplicada a todas las respuestas; no hay parámetros ni valores alternativos válidos. Ponla en el borde (CDN) para cubrir todo el sitio, o en el servidor web con semántica always para que se emita también en respuestas de error, y luego confírmala en las cabeceras de respuesta.

Preguntas frecuentes

No dejamos que nadie suba archivos. ¿Aun así lo necesitamos?

Sí, y sigue mereciendo la pena hacerlo. La cabecera es defensa en profundidad: también impide que el navegador malinterprete scripts, hojas de estilo y archivos de datos servidos desde tu propio sitio, lo que protege frente a varios trucos de cross-site scripting incluso en sitios sin formulario de subida. No cuesta nada y nunca rompe un sitio bien configurado, así que no hay razón para saltársela.

¿Añadir esto romperá algo en nuestro sitio web?

Casi nunca. nosniff simplemente hace que los navegadores respeten el tipo de contenido que tu servidor ya envía. La única manera de que cause problemas es si tu servidor está etiquetando mal los archivos, por ejemplo enviando una hoja de estilo o un script con el tipo equivocado. Si algo se rompe, es un fallo real que nosniff expuso, no que causó, y conviene arreglarlo de todos modos. Prueba una vez tras el despliegue.

¿Cómo es realmente lo «bueno»?

Una sola cabecera de respuesta en cada página y recurso: X-Content-Type-Options: nosniff. Esa es toda la configuración correcta; no hay otros valores válidos ni ajustes que tocar.

Nuestro CDN (Cloudflare o similar) y nuestro servidor la añaden los dos. ¿Es un problema?

No. Ver el valor dos veces («nosniff, nosniff») porque tanto el CDN como el origen lo establecen es perfectamente correcto y sigue pasando. No hace falta quitar ninguno.

¿Arreglar esto cuesta dinero?

No. La solución es una línea de configuración gratuita en tu servidor web o CDN. Quien te cobre por añadir una sola cabecera te está cobrando de más. Lo único que merece la pena pagar en esta área es la monitorización continua, una vista de cartera de muchos sitios o una auditoría formal, no la solución en sí.

¿En qué se diferencia esto de una Content Security Policy (CSP)?

Son complementarias. La CSP controla qué scripts y recursos pueden cargarse siquiera; nosniff impide que el navegador clasifique mal un archivo que sí carga. Conviene tener ambas. nosniff es mucho más simple y rápida de añadir, así que es un buen primer paso de camino a una CSP completa.