Security-Header-Architektur für Spring Boot

Alle Security Headers in einer zentralen SecurityFilterChain konfigurieren -- von Spring Security Defaults über die headers()-DSL bis zur Verifizierung.

Spring Boot · Schritt für Schritt

Konsolidierte Security Headers in Spring Boot

Spring Boot mit Spring Security 6.x bietet eine integrierte Header-Verwaltung ueber die SecurityFilterChain-API. Im Gegensatz zu vielen anderen Frameworks setzt Spring Security bereits vier Header automatisch. Alle weiteren Header konfigurieren Sie in einer einzigen @Configuration-Klasse.

Diese Anleitung zeigt die vollständige Implementierung: von der @Bean SecurityFilterChain-Methode über die Default-Header bis zur Verifizierung. Der Code ist direkt in Ihr Spring Boot 3.x Projekt kopierbar.

1 Schritt 1 von 4

Spring Security Default-Header verstehen

Spring Security setzt vier Header automatisch, sobald Spring Security im Classpath liegt. Diese Defaults sind sinnvoll, müssen aber für viele Anwendungsfaelle angepasst werden. Verstehen Sie zuerst, was bereits aktiv ist, bevor Sie weitere Header hinzufuegen.

Spring Security 6.x Defaults Automatisch
// Von Spring Security 6.x automatisch gesetzte Header:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 0

// NICHT automatisch gesetzt (manuell konfigurieren):
Content-Security-Policy
Strict-Transport-Security
Referrer-Policy
Permissions-Policy
Cross-Origin-Opener-Policy
Cross-Origin-Resource-Policy
Cross-Origin-Embedder-Policy
X-Frame-Options: DENY vs. SAMEORIGIN

Spring Security setzt standardmaessig DENY. Falls Ihre Anwendung iframes verwendet (z.B. für eingebettete Dashboards), ändern Sie auf SAMEORIGIN per frameOptions(fo -> fo.sameOrigin()).

2 Schritt 2 von 4

SecurityFilterChain mit allen Headern

Erstellen Sie eine SecurityConfig-Klasse mit der @Configuration-Annotation. Die @Bean SecurityFilterChain-Methode konfiguriert alle Security Headers an einem Ort. Spring Security wendet diese Konfiguration auf alle HTTP-Responses an.

src/main/java/com/example/config/SecurityConfig.java Konsolidiert
// src/main/java/com/example/config/SecurityConfig.java
package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.header.writers.*;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http)
            throws Exception {

        http.headers(headers -> headers
            // --- CSP (nicht als Default gesetzt) ---
            .contentSecurityPolicy(csp -> csp
                .policyDirectives("default-src 'self'; script-src 'self'; "
                    + "style-src 'self' 'unsafe-inline'; "
                    + "img-src 'self' data: https:; "
                    + "font-src 'self'; object-src 'none'; "
                    + "frame-ancestors 'self'; base-uri 'self'; "
                    + "form-action 'self'"))

            // --- HSTS (nicht als Default gesetzt) ---
            .httpStrictTransportSecurity(hsts -> hsts
                .includeSubDomains(true)
                .maxAgeInSeconds(31536000)
                .preload(true))

            // --- Referrer-Policy (nicht als Default) ---
            .referrerPolicy(referrer -> referrer
                .policy(ReferrerPolicyHeaderWriter.ReferrerPolicy
                    .STRICT_ORIGIN_WHEN_CROSS_ORIGIN))

            // --- Permissions-Policy (nicht als Default) ---
            .permissionsPolicy(pp -> pp
                .policy("camera=(), microphone=(), geolocation=(), payment=()"))

            // --- X-Frame-Options: Default ist DENY ---
            // Auf SAMEORIGIN ändern wenn iframes noetig:
            .frameOptions(fo -> fo.sameOrigin())

            // --- X-Content-Type-Options: Default nosniff ---
            // --- Cache-Control: Default no-cache ---
            // --- X-XSS-Protection: Default 0 ---
            // Diese drei werden automatisch gesetzt
        );

        return http.build();
    }
}
Warum SecurityFilterChain statt WebSecurityConfigurerAdapter?

WebSecurityConfigurerAdapter ist seit Spring Security 5.7 deprecated und in 6.0 entfernt. Die @Bean SecurityFilterChain-Methode ist der aktuelle Standard für Spring Boot 3.x und bietet bessere Komposition mehrerer Sicherheitskonfigurationen.

3 Schritt 3 von 4

Empfohlene Header-Reihenfolge

Die Reihenfolge in der headers()-DSL beeinflusst nicht die Browser-Verarbeitung, aber eine konsistente Struktur erleichtert Audits und Wartung. Wolf-Agents empfiehlt diese Reihenfolge nach Sicherheitsrelevanz.

1
Content-Security-Policy 35 Pkt
Wichtigster Header -- XSS-Schutz, manuell konfigurieren
2
Strict-Transport-Security 15 Pkt
HTTPS erzwingen, manuell konfigurieren
3
Permissions-Policy + Referrer-Policy 20 Pkt
Manuell konfigurieren -- kein Default
4
X-Frame-Options + X-Content-Type-Options 20 Pkt
Spring Security Defaults -- bei Bedarf anpassen
5
Cross-Origin Headers 30+ Pkt
CORP, COEP, COOP -- manuell konfigurieren
4 Schritt 4 von 4

Konfiguration verifizieren

Starten Sie die Anwendung und prüfen Sie die Response-Header. Alle konfigurierten Header müssen in der Antwort sichtbar sein. Verwenden Sie den Wolf-Agents Web Security Check für eine vollständige Analyse.

Terminal Verifizierung
# Spring Boot Anwendung starten
./mvnw spring-boot:run
# oder mit Gradle
./gradlew bootRun

# Security Headers prüfen
curl -sI http://localhost:8080 | grep -iE "content-security|strict-transport|x-frame|referrer|x-content-type|permissions-policy"

# Erwartete Ausgabe:
cache-control: no-cache, no-store, max-age=0, must-revalidate
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: default-src 'self'; script-src 'self'; ...
strict-transport-security: max-age=31536000; includeSubDomains; preload
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=(), payment=()
Wenn Sie einen Reverse Proxy (z.B. Nginx) vor Spring Boot betreiben, prüfen Sie, ob der Proxy Header überschreibt. Spring-Boot-Header können durch Proxy-Konfigurationen verloren gehen oder doppelt gesetzt werden.

Häufige Fehler bei Spring Boot Security Headers

@Order falsch gesetzt bei mehreren SecurityFilterChains

Bei mehreren SecurityFilterChain-Beans wird die mit der niedrigsten @Order-Nummer zuerst ausgewertet. Ohne explizite @Order-Annotation kann Ihre Header-Konfiguration von einer anderen FilterChain ueberschrieben werden.

Actuator-Endpoints ohne Security Headers

Wenn Actuator auf dem gleichen Port laeuft, teilt es die SecurityFilterChain. Bei separatem Management-Port (management.server.port) benoetigen Actuator-Endpoints eine eigene Header-Konfiguration.

WebFlux- und WebMVC-Config verwechselt

WebMVC verwendet HttpSecurity und SecurityFilterChain. WebFlux verwendet ServerHttpSecurity und SecurityWebFilterChain. Die Klassen sind nicht austauschbar -- verwechselte Imports fuehren zu Startfehlern.

Profile dev hat permissive Header auf Produktion

Wenn Sie @Profile("dev") für lockere Header nutzen, stellen Sie sicher, dass @Profile("prod") die produktiven Header definiert. Vergessene Profile-Umschaltung fuehrt zu fehlenden Headern in Produktion.

Compliance-Anforderungen

Eine konsolidierte SecurityFilterChain-Architektur unterstuetzt direkt die Anforderungen mehrerer Compliance-Frameworks. Die zentrale Verwaltung aller Security Headers in einer Java-Klasse vereinfacht Audits erheblich.

PCI DSS 4.0 -- Requirement 6.4.3 verlangt dokumentierte Security-Header-Konfigurationen. Eine SecurityConfig-Klasse im Git ist die Dokumentation.
NIS2 -- Artikel 21 fordert technische Massnahmen zur Cyber-Sicherheit. Security Headers sind eine Basismassnahme.
OWASP ASVS -- Level 1 (V14.4) fordert Security Headers. Die SecurityFilterChain deckt alle relevanten Header ab.

Wie steht Ihre Domain bei Implementierungs-Architektur?

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