CSP für Spring Boot konfigurieren

Content Security Policy in Spring Boot einrichten -- mit SecurityFilterChain, dynamischen Nonces per OncePerRequestFilter und Thymeleaf-Integration.

Spring Boot · Schritt für Schritt

Content Security Policy in Spring Boot

Content Security Policy (CSP) ist der wichtigste HTTP-Security-Header gegen Cross-Site Scripting (XSS). Er definiert, welche Ressourcen der Browser laden darf, und blockiert alles andere. CSP ist mit 35 von 166 Punkten der einflussreichste Header im Wolf-Agents Web Security Check.

Spring Security setzt CSP nicht automatisch. Sie müssen den Header explizit in der SecurityFilterChain konfigurieren. Für statische Policies reicht die contentSecurityPolicy()-DSL. Für dynamische Nonces benoetigen Sie einen OncePerRequestFilter, der pro Request einen Nonce generiert und als Request-Attribut für Thymeleaf verfügbar macht.

1 Schritt 1 von 4

CSP im Report-Only-Modus starten

Beginnen Sie immer im Report-Only-Modus. Spring Security bietet dafür keine eigene DSL -- verwenden Sie stattdessen den Header-Namen Content-Security-Policy-Report-Only direkt. Der Browser meldet Verstoesse in der Konsole, blockiert aber keine Ressourcen.

SecurityConfig.java Report-Only
// SecurityConfig.java -- Report-Only CSP
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)
        throws Exception {

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

    return http.build();
}
Profile-basierte Konfiguration

Verwenden Sie @Profile("prod") für die Enforcement-Konfiguration und @Profile("dev") für eine lockere CSP. So können Sie lokal mit 'unsafe-inline' entwickeln, während Produktion strikte Nonces erzwingt.

2 Schritt 2 von 4

Violations analysieren

Oeffnen Sie die Browser DevTools (F12) und prüfen Sie die Console. CSP-Violations erscheinen als Warnungen mit der blockierten Ressource und der verletzten Direktive.

Violation Loesung
Thymeleaf Inline-Script blockiert Nonce per th:attr="nonce=${cspNonce}" hinzufuegen
Webjars-Ressourcen blockiert /webjars/**-Pfad in script-src erlauben oder Nonces nutzen
Spring Boot DevTools blockiert LiveReload-Port in connect-src erlauben (nur Dev-Profil)
Actuator-Endpoint blockiert Separate CSP für /actuator/** mit eigener SecurityFilterChain
Lassen Sie die Policy mindestens 1 Woche im Report-Only-Modus laufen. Testen Sie alle Seitentypen -- inklusive Login, Dashboard und Admin-Bereich.
3 Schritt 3 von 4

Nonces mit OncePerRequestFilter

Für maximale Sicherheit verwenden Sie dynamische Nonces. Der OncePerRequestFilter generiert pro Request einen kryptographisch sicheren Nonce und setzt ihn als Request-Attribut. Thymeleaf-Templates können den Nonce dann per ${cspNonce} referenzieren.

CspNonceFilter.java Produktiv
// src/main/java/com/example/filter/CspNonceFilter.java
package com.example.filter;

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import org.springframework.web.filter.OncePerRequestFilter;
import java.security.SecureRandom;
import java.util.Base64;

@Component
public class CspNonceFilter extends OncePerRequestFilter {

    private static final SecureRandom RANDOM = new SecureRandom();

    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain) throws Exception {

        // Nonce generieren (22 Zeichen Base64)
        byte[] bytes = new byte[16];
        RANDOM.nextBytes(bytes);
        String nonce = Base64.getEncoder().encodeToString(bytes);

        // Nonce als Request-Attribut fuer Thymeleaf
        request.setAttribute("cspNonce", nonce);

        // CSP-Header mit Nonce setzen
        String csp = "default-src 'self'; "
            + "script-src 'self' 'nonce-" + nonce + "' 'strict-dynamic'; "
            + "style-src 'self' 'unsafe-inline'; "
            + "img-src 'self' data: https:; "
            + "font-src 'self'; "
            + "connect-src 'self'; "
            + "object-src 'none'; "
            + "frame-ancestors 'self'; "
            + "base-uri 'self'; "
            + "form-action 'self'";

        response.setHeader("Content-Security-Policy", csp);

        filterChain.doFilter(request, response);
    }
}
Thymeleaf-Template Nonces
<!-- Thymeleaf-Template: Nonce verwenden -->
<script th:attr="nonce=${cspNonce}">
  console.log('Autorisiertes Script mit Nonce');
</script>

<!-- Externe Scripts mit Nonce -->
<script th:attr="nonce=${cspNonce}"
        src="/js/app.js"></script>
4 Schritt 4 von 4

Verifizierung

Prüfen Sie den CSP-Header mit curl. Der Nonce aendert sich bei jedem Request -- das ist korrekt und gewuenscht.

Terminal Verifizierung
# CSP-Header pruefen
curl -sI http://localhost:8080 | grep -i content-security-policy

# Erwartete Ausgabe:
content-security-policy: default-src 'self'; script-src 'self' 'nonce-abc123...' 'strict-dynamic'; ...

Häufige Fehler bei CSP in Spring Boot

SecurityFilterChain und OncePerRequestFilter setzen beide CSP

Wenn sowohl die contentSecurityPolicy()-DSL als auch ein OncePerRequestFilter den CSP-Header setzen, entstehen doppelte Header. Verwenden Sie für Nonces ausschliesslich den Filter und entfernen Sie die CSP-Konfiguration aus der SecurityFilterChain.

CORS-Config kollidiert mit CSP connect-src

Spring Boots @CrossOrigin oder CorsConfigurationSource erlaubt Cross-Origin-Requests auf Server-Seite, aber CSP blockiert sie im Browser. Fuegen Sie erlaubte Origins auch in die connect-src-Direktive ein.

Static Resources haben andere CSP als Controller-Responses

Statische Dateien unter /static/** werden standardmaessig mit den gleichen Headern wie Controller-Responses ausgeliefert. Wenn Ihr Nonce-Filter nur Controller-Requests verarbeitet, fehlt der Nonce auf statischen Seiten.

Profile dev hat unsafe-inline -- vergessen umzuschalten

Ein Dev-Profil mit 'unsafe-inline' in script-src ist bequem zum Entwickeln. Wenn das falsche Profil auf Produktion aktiv ist, fehlt der XSS-Schutz. Prüfen Sie das aktive Profil nach jedem Deployment mit /actuator/env.

Compliance-Anforderungen

Content Security Policy ist eine zentrale Anforderung mehrerer Compliance-Frameworks und besonders relevant für Spring-Boot-Anwendungen, die sensible Daten verarbeiten.

PCI DSS 4.0 -- Requirement 6.4.3 fordert explizit CSP-Header für alle Seiten, die Zahlungsdaten verarbeiten.
NIS2 -- Artikel 21(e) fordert Sicherheit bei Entwicklung und Wartung von Netz- und Informationssystemen.
OWASP ASVS -- Level 2 (V14.4.3) fordert CSP mit Nonces oder Hashes. Der OncePerRequestFilter erfuellt diese Anforderung.

Wie steht Ihre Domain bei Content Security Policy?

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