X-Content-Type-Options es una cabecera de respuesta HTTP que tiene exactamente un único valor válido: nosniff. Indica al navegador que respete estrictamente el tipo MIME declarado en la cabecera Content-Type y que nunca intente adivinar el tipo de contenido por su cuenta. Esto previene una categoría de ataques que explotan el comportamiento de sniffing de tipo MIME del navegador.
De todas las cabeceras de seguridad, X-Content-Type-Options es la más sencilla de entender e implementar. Requiere una sola línea de configuración, no tiene directivas complejas y prácticamente no hay motivo para no usarla. Aun así, un número sorprendente de sitios sigue sin enviarla.
Qué es el sniffing de tipo MIME y por qué los navegadores lo hacen
Para entender por qué existe esta cabecera, necesitas un poco de historia. En los primeros días de la web, muchos servidores estaban mal configurados y enviaban cabeceras Content-Type incorrectas. Un servidor podía servir un archivo HTML como text/plain, o una imagen como application/octet-stream. Si los navegadores hubieran respetado estrictamente el tipo declarado, esas páginas se habrían mostrado como texto en bruto o habrían provocado una descarga en lugar de mostrarse correctamente.
Para sortearlo, los navegadores empezaron a "olfatear" (sniffing) el contenido real de los archivos para determinar su tipo verdadero. El navegador miraba los primeros bytes de una respuesta, comprobaba firmas conocidas (como etiquetas <html>, cabeceras de imagen o patrones de JavaScript) y anulaba el tipo declarado por el servidor si el contenido parecía distinto. Internet Explorer era especialmente agresivo con esto. Si IE detectaba algo que parecía HTML o JavaScript dentro de un archivo servido como text/plain, lo renderizaba o ejecutaba sin problema.
Era un apaño razonable para servidores mal configurados, pero creó un grave agujero de seguridad.
Cómo el sniffing MIME habilita ataques
Aquí tienes un escenario de ataque concreto dirigido a un sitio WordPress con subida de archivos:
Supongamos que tu sitio WordPress permite a los usuarios subir fotos de perfil. Tu manejador de subidas comprueba la extensión del archivo y solo permite .jpg, .png y .gif. Un atacante crea un archivo que comienza con cabeceras de imagen válidas (los primeros bytes parecen un JPEG correcto) pero contiene código JavaScript incrustado tras la cabecera de la imagen. Lo nombra avatar.jpg y lo sube.
Tu servidor almacena el archivo y lo sirve con Content-Type: image/jpeg. Hasta aquí, todo parece correcto. Pero ahora el atacante enlaza a este archivo desde una página, quizá en un foro o en un comentario, usando una etiqueta script:
<script src="https://tusitio.com/uploads/avatar.jpg"></script>Sin X-Content-Type-Options, un navegador que aplique sniffing MIME podría mirar el archivo, notar que contiene contenido similar a JavaScript y ejecutarlo como script a pesar del Content-Type image/jpeg. El JavaScript del atacante se ejecuta entonces en el contexto de tu sitio, con acceso a las cookies y a los datos de sesión de tus visitantes.
Con la cabecera nosniff, el navegador respeta el tipo declarado image/jpeg y se niega a ejecutar el archivo como JavaScript. El ataque falla.
Sniffing MIME y subidas de medios en WordPress
WordPress dispone de un sistema de subida de medios que gestiona muchos archivos: imágenes, PDFs, documentos, audio, vídeo. Cada uno se sirve con un tipo MIME específico. El núcleo de WordPress ya hace cierta validación en las subidas (comprobando los tipos de archivo frente a una lista permitida, verificando que el contenido del archivo coincide con la extensión), pero estas comprobaciones no son infalibles.
Varios factores hacen que WordPress sea especialmente relevante aquí:
- Múltiples puntos de subida: la biblioteca de medios, Gravity Forms, Contact Form 7, las imágenes de productos de WooCommerce, los adjuntos en foros bbPress y muchos otros plugins gestionan subidas de archivos. Cada uno es un posible punto de entrada para archivos maliciosos.
- Contenido generado por usuarios: en sitios con funciones de membresía o comunidad, puedes permitir que usuarios relativamente poco fiables suban archivos. Cuantas más fuentes de subida tengas, más importante es que el navegador trate los archivos exactamente como se han declarado.
- Manejadores de subida en plugins: no todos los plugins validan las subidas con el mismo cuidado que el núcleo de WordPress. Un plugin mal escrito podría aceptar archivos con tipos no coincidentes, creando justo las condiciones que explotan los ataques de sniffing MIME.
- Entornos de hosting compartido: en hosting compartido, archivos de otros sitios del mismo servidor podrían servirse potencialmente con cabeceras incorrectas. La directiva
nosniffañade una capa de defensa con independencia de la calidad de la configuración del servidor.
La cabecera de seguridad más sencilla de implementar
Añadir X-Content-Type-Options requiere una sola línea. No hay directivas que elegir, no hay valores que ajustar y no hay riesgo de romper funcionalidades. A diferencia de CSP (que puede romper scripts inline), HSTS (que puede dejarte fuera si caduca tu certificado) o Referrer-Policy (que puede afectar a la analítica), X-Content-Type-Options prácticamente no tiene inconvenientes.
Para Apache (configuración .htaccess o virtual host):
Header always set X-Content-Type-Options "nosniff"Para Nginx:
add_header X-Content-Type-Options "nosniff" always;Mediante PHP en WordPress:
add_action('send_headers', function() {
header('X-Content-Type-Options: nosniff');
});WordPress por sí solo ya envía X-Content-Type-Options: nosniff para las páginas de administración y las respuestas de la REST API desde la versión 4.8. Sin embargo, las páginas del front-end de la mayoría de instalaciones de WordPress no incluyen esta cabecera a menos que la añadas a nivel de servidor o mediante un plugin de seguridad.
Cómo gestionan los navegadores modernos el sniffing MIME
El comportamiento de los navegadores ha mejorado significativamente con los años. Las versiones modernas de Chrome, Firefox, Safari y Edge son mucho menos agresivas con el sniffing MIME que los navegadores de la era de Internet Explorer. Chrome, por ejemplo, ya bloquea scripts que tienen un tipo MIME no de script en muchas situaciones, incluso sin la cabecera nosniff.
No obstante, sigue habiendo casos extremos donde el sniffing ocurre, y los navegadores antiguos pueden ser todavía vulnerables. La cabecera nosniff proporciona una instrucción clara y definitiva que elimina toda ambigüedad. Es una buena práctica con independencia de los navegadores que utilicen tus visitantes.
Interacción con otras cabeceras de seguridad
X-Content-Type-Options funciona bien junto a otras cabeceras de seguridad y no hay conflictos de los que preocuparse:
- Combinada con CSP, proporciona defensa en profundidad: CSP controla qué orígenes están permitidos, mientras que
nosniffgarantiza que los archivos de orígenes permitidos se traten como su tipo declarado. - Con HSTS, te aseguras de que las conexiones están cifradas, y con
nosniffgarantizas además la integridad del contenido. - A diferencia de otras cabeceras,
nosniffno interactúa ni anula ninguna otra cabecera. Es puramente aditiva.
Qué comprueba InspectWP
InspectWP comprueba si tu sitio WordPress envía la cabecera X-Content-Type-Options: nosniff. Como esta cabecera solo tiene un valor válido y ninguna complejidad de configuración, realmente no hay motivo para que esté ausente. Si a tu sitio le falta esta cabecera, es una de las victorias de seguridad más rápidas que puedes lograr. Añadirla lleva menos de un minuto y proporciona una protección significativa frente a ataques de confusión de tipo MIME, especialmente en sitios que gestionan subidas de archivos.