Was ist MIME-Sniffing?
Wenn ein Browser eine Datei vom Server lädt, sagt der Server per
Content-Type-Header, was es ist —
text/html,
image/png,
application/javascript
und so weiter. Was passiert aber, wenn der Server keinen Content-Type schickt oder einen
offensichtlich falschen (z. B. eine .gif-Datei mit
text/plain)?
Hier kam historisch MIME-Sniffing ins Spiel: Browser haben in die ersten paar Bytes der Datei geschaut und versucht, den Typ selbst zu erkennen. Sieht aus wie HTML? Dann als HTML rendern, egal was der Header sagt. Das war im frühen Web pragmatisch — viele Server haben Content-Types damals schlampig gesetzt — heute ist es eine Sicherheitslücke.
Das Sicherheitsproblem
Stellen wir uns vor: Auf deiner Webseite kann ein Nutzer Dateien hochladen — etwa
Profilbilder. Der Angreifer lädt eine Datei hoch, die wie ein gültiges PNG aussieht,
aber im Body HTML mit eingebettetem JavaScript enthält. Der Server gibt sie mit
image/png aus — soweit, so unkritisch.
Ein Browser ohne Sniffing würde das Bild laden, das Skript würde nie ausgeführt.
Aber: Hat der Browser Sniffing aktiv und entdeckt im Body HTML-Markup, rendert er die Datei plötzlich als HTML — das eingebettete JavaScript läuft im Kontext deiner Domain und kann auf Cookies, Session und alle Daten der eingeloggten Nutzer zugreifen. Aus einem gemütlichen Datei-Upload wird ein vollständiger XSS-Angriff.
Das gleiche Problem existiert auch andersherum: Eine harmlose Textdatei kann je nach Browser-Sniffing-Logik plötzlich als Skript ausgeführt werden, eine PDF-Datei als HTML usw. Klassiker auch: alte Adobe-Flash-basierte Sniffing-Bypässe.
Die Lösung: nosniff
Der Header
X-Content-Type-Options: nosniff
sagt dem Browser unmissverständlich:
"Vertraue ausschließlich dem Content-Type-Header. Mach kein Sniffing. Wenn ich sage,
etwas ist image/png, dann lade
es als Bild — und nichts anderes."
Mit nosniff wird der oben beschriebene Upload-Angriff wirkungslos: Der Browser sieht
Content-Type: image/png und behandelt
die Datei strikt als Bild. Auch wenn HTML drin ist — kein Rendern, kein Skript.
Voraussetzung: Der Server schickt einen sinnvollen Content-Type. Bei einem fehlenden
Header bleibt nosniff trotzdem konservativ und lädt die Datei nicht als ausführbar.
Werte
Der Header kennt nur einen einzigen sinnvollen Wert:
nosniff. Alles andere wird ignoriert.
X-Content-Type-Options: nosniff
Konfigurationsbeispiele
nginx:
add_header X-Content-Type-Options "nosniff" always;
Apache:
Header always set X-Content-Type-Options "nosniff"
Express:
app.use(helmet.noSniff())
Cloudflare: Im Dashboard unter Rules → Transform Rules → Modify Response Header.
Voraussetzung: korrekte Content-Types
nosniff wirkt nur, wenn dein Server tatsächlich die richtigen Content-Types
ausliefert. Ein Bild als text/plain
lädt nicht mehr — nosniff blockiert es. Schlecht konfigurierte Servers können nach dem
Aktivieren von nosniff plötzlich Funktionsprobleme bekommen.
Lösung: vor dem Aktivieren prüfen, dass alle gängigen Dateitypen korrekte MIME-Types
bekommen — bei nginx wird das über /etc/nginx/mime.types
geregelt, was meistens schon passt. Bei Apache wird in der Regel kein Eingriff benötigt.
Fazit
X-Content-Type-Options: nosniff ist
einer der einfachsten Security-Header — keine Konfigurationsmöglichkeiten, kein
Trade-off, einfach setzen. Für jede Webseite mit Datei-Uploads, User-Generated-Content
oder API-Endpunkten Pflicht. Im Webscan Radar findest du den Header in der Liste der
sechs überprüften Security-Header.