Alle Artikel
Ein Spring Boot RestController auf embedded Tomcat prüft Webhook-Signatur-Header aus Raw-byte[]-Payload über einen lokalen Tunnel.
Spring BootJavawebhook debugginglocal testing

Spring Boot-Webhooks: Raw Body, CSRF-Ausnahme, Signatur-Header

Spring Boot macht Webhook-Endpoints mit @RestController einfach, aber Spring Security CSRF und JSON-Converter können Payloads blockieren oder verändern, bevor der Handler läuft. Lokales Testen soll Raw-byte[]-Zugriff, CSRF-Ausnahmen auf Webhook-Pfaden und Signaturprüfung auf unveränderten Bytes beweisen.

@RestController-Webhook-Endpoint anlegen

Webhook-Controller schlank halten. Raw Bytes annehmen, Signatur prüfen, dann deserialisieren:

@RestController
@RequestMapping("/webhooks")
public class StripeWebhookController {

    @PostMapping("/stripe")
    public ResponseEntity handle(
            @RequestBody byte[] payload,
            @RequestHeader("Stripe-Signature") String signature) {

        if (!verifier.isValid(payload, signature)) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        }
        JsonNode event = objectMapper.readTree(payload);
        handler.process(event);
        return ResponseEntity.ok().build();
    }
}

@RequestBody byte[] erhält den exakten Payload von Tomcat — ideal wenn Anbieter rohes JSON signieren.

Raw-Body über HttpServletRequest lesen

Alternativ direkt aus der Servlet-Request lesen:

byte[] body = request.getInputStream().readAllBytes();
String sig = request.getHeader("Stripe-Signature");

Nicht zuerst an POJO oder Map binden — Jackson-Re-Serialisierung bricht HMAC. Siehe Leitfaden zur Signaturprüfung.

CSRF nur für Webhook-Pfade deaktivieren

Spring Security aktiviert CSRF standardmäßig. Webhook-POSTs scheitern mit 403 ohne server-to-server-Ausnahme:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.ignoringRequestMatchers("/webhooks/**"));
        return http.build();
    }
}

Ignore-Pattern auf /webhooks/** begrenzen — CSRF nicht global abschalten.

Signatur-Header vor Business-Logik prüfen

Provider-Header lesen, Digest aus dem Byte-Array berechnen, constant-time vergleichen. Bei Mismatch 401, bei Erfolg schnell 200 für weniger Retries.

Lokaler Tunnel-Workflow

  1. App starten: ./mvnw spring-boot:run auf Port 8080.
  2. Tomcat exponieren: npx portpreview 8080.
  3. Tunnel-URL + Pfad ins Provider-Dashboard.
  4. Test-Event senden und Logs beobachten.
  5. Gleiche Event-ID wiederholen für Idempotenz — siehe Retry-Muster.

Häufige Stolperfallen

Filter-Reihenfolge und Body-Verbrauch

Filter die den Stream vor dem Controller lesen, hinterlassen leeren Stream. ContentCachingRequestWrapper nutzen wenn nötig.

Globales @RequestBody-Binding

Globales @ControllerAdvice das JSON früh parst, kann Bytes ändern. Webhook-Endpoints mit byte[] isolieren.

Langsame Handler lösen Retries aus

Schnell bestätigen, async verarbeiten, per Event-ID deduplizieren.

Weiterführend

Grundlagen finden Sie unter localhost-Tunneling-Grundlagen und praktisches lokales Webhook-Debugging. Zur Signaturmechanik siehe den Leitfaden zur Signaturprüfung. Für duplikatsichere Handler lesen Sie Retry- und Idempotenz-Muster. starten Sie PortPreview kostenlos.

Häufig gestellte Fragen

Warum geben Spring Boot Webhooks 403 zurück?
Spring Security CSRF blockiert POSTs ohne Session-Token. csrf.ignoringRequestMatchers für den Webhook-Pfad hinzufügen und Signaturen prüfen.
byte[] oder POJO für Webhooks?
Nutze byte[] für die Signaturprüfung. POJO-Binding serialisiert JSON neu und bricht HMAC.
Wie teste ich Spring Boot Webhooks lokal?
spring-boot:run auf 8080, mit npx portpreview exponieren, Tunnel-URL einfügen und Test-Events auslösen.