X-Content-Type-Options in Spring Boot

Spring Security setzt nosniff automatisch -- verifizieren Sie den Default, konfigurieren Sie korrekte Content-Types und schuetzen Sie auch Actuator-Endpoints.

Spring Boot · Schritt für Schritt

MIME-Sniffing-Schutz in Spring Boot

X-Content-Type-Options: nosniff verhindert, dass Browser den MIME-Type einer Ressource erraten (MIME-Sniffing). Ohne diesen Header koennten Angreifer eine als Bild getarnte JavaScript-Datei einschleusen. Der Header ist mit 10 von 166 Punkten im Wolf-Agents Web Security Check bewertet.

Spring Security setzt X-Content-Type-Options: nosniff automatisch als Default. Das bedeutet: Ihre Spring-Boot-Anwendung ist standardmaessig geschützt. Trotzdem sollten Sie den Header verifizieren und sicherstellen, dass alle Responses korrekte Content-Type-Header setzen -- denn nosniff erzwingt den deklarierten MIME-Type.

1Schritt 1 von 3

Spring Security Default verifizieren

Spring Security setzt X-Content-Type-Options: nosniff automatisch für alle Responses, die durch die SecurityFilterChain laufen. Verifizieren Sie den Header per curl. Wenn Sie den Default explizit machen wollen, verwenden Sie contentTypeOptions(Customizer.withDefaults()).

SecurityConfig.javaDefault
// SecurityConfig.java -- X-Content-Type-Options (Default)
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)
        throws Exception {

    // Spring Security setzt X-Content-Type-Options: nosniff
    // automatisch -- keine explizite Konfiguration noetig.
    // Falls Sie den Default explizit machen wollen:
    http.headers(headers -> headers
        .contentTypeOptions(Customizer.withDefaults())
    );

    return http.build();
}

// WARNUNG: Header NIEMALS deaktivieren!
// http.headers(h -> h.contentTypeOptions(cto -> cto.disable()));
Nicht deaktivieren!

Im Gegensatz zu anderen Security-Headern gibt es keinen legitimen Grund, nosniff zu deaktivieren. Die disable()-Methode existiert, sollte aber niemals verwendet werden.

2Schritt 2 von 3

Content-Types korrekt konfigurieren

Da nosniff den Browser zwingt, den deklarierten MIME-Type zu verwenden, müssen alle Responses den korrekten Content-Type Header setzen. Falsche Content-Types fuehren dazu, dass Ressourcen nicht geladen werden.

ApiController.javaProduktiv
// Controller mit korrektem Content-Type
@RestController
public class ApiController {

    @GetMapping(value = "/api/data",
        produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Map<String, Object>> getData() {
        return ResponseEntity.ok()
            .contentType(MediaType.APPLICATION_JSON)
            .body(Map.of("status", "ok"));
    }

    // Datei-Downloads mit korrektem MIME-Type
    @GetMapping("/download/{filename}")
    public ResponseEntity<byte[]> download(
            @PathVariable String filename) {
        byte[] content = loadFile(filename);
        String mimeType = detectMimeType(filename);
        return ResponseEntity.ok()
            .header("Content-Type", mimeType)
            .header("Content-Disposition",
                "attachment; filename="" + filename + """)
            .body(content);
    }
}
Der Wolf-Agents Web Security Check prüft diesen Header automatisch und bewertet ihn mit bis zu 10 Punkten.
3Schritt 3 von 3

Actuator-Endpoints absichern

Spring Boot Actuator-Endpoints liefern JSON-Daten mit sensiblen Informationen. Stellen Sie sicher, dass auch diese Endpoints den nosniff-Header setzen. Bei separaten SecurityFilterChains muss jede Chain die Header-Konfiguration enthalten.

SecurityConfig.java + application.ymlProduktiv
// application.yml -- Actuator mit Security Headers
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics

// Separate SecurityFilterChain fuer Actuator
@Bean
@Order(1)
public SecurityFilterChain actuatorSecurity(HttpSecurity http)
        throws Exception {
    http.securityMatcher("/actuator/**")
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/actuator/health").permitAll()
            .anyRequest().hasRole("ADMIN"))
        .headers(headers -> headers
            .contentTypeOptions(Customizer.withDefaults()));
    return http.build();
}
4Verifizierung

Header verifizieren

Prüfen Sie den X-Content-Type-Options-Header mit curl. Der Wert muss nosniff sein -- es gibt nur diesen einen gueltigen Wert.

TerminalVerifizierung
# X-Content-Type-Options pruefen
curl -sI http://localhost:8080 | grep -i x-content-type-options

# Erwartete Ausgabe (Spring Security Default):
x-content-type-options: nosniff

Häufige Fehler bei X-Content-Type-Options in Spring Boot

nosniff deaktiviert wegen Content-Type-Problemen

Wenn Ressourcen nach Aktivierung von nosniff nicht laden, ist der Content-Type falsch konfiguriert -- nicht der Security-Header. Korrigieren Sie den MIME-Type statt nosniff zu deaktivieren.

Separate SecurityFilterChain ohne Header-Config

Wenn Sie mehrere SecurityFilterChain-Beans definieren (z.B. für Actuator und API), erbt jede Chain nur die Header, die Sie explizit konfigurieren. Vergessene Chains liefern keine Security-Header.

Statische Ressourcen per web.ignoring() ausgeschlossen

Wenn Sie web.ignoring().requestMatchers("/static/**") verwenden, umgehen diese Requests die gesamte SecurityFilterChain -- inklusive nosniff. Verwenden Sie stattdessen permitAll().

Actuator-Endpoints ohne Security Headers

Actuator-Endpoints unter /actuator/** können bei falscher Konfiguration ohne Security-Header ausgeliefert werden. Definieren Sie eine eigene SecurityFilterChain mit @Order(1) für Actuator.

Compliance-Relevanz

X-Content-Type-Options ist ein grundlegender Security-Header, der in verschiedenen Compliance-Frameworks gefordert wird.

OWASP ASVS -- V14.4.4 fordert den nosniff-Header für alle Responses zur Verhinderung von MIME-Sniffing.
NIS2 -- Art. 21(e) fordert sichere Konfiguration von Netz- und Informationssystemen.
BSI -- APP.3.1 empfiehlt X-Content-Type-Options als Basis-Security-Header für Webserver.

Wie steht Ihre Domain bei X-Content-Type-Options?

Prüfen Sie es jetzt — kostenlos, ohne Registrierung, mit 166 Prüfpunkte.