Einblicke & Fachbeiträge

So habe ich mein produktives Next.js-SaaS gegen SSRF und Stripe-Webhook-Angriffe abgesichert

März 2026 · Damir Andrijanic · 6 Min. Lesezeit

Security-Playbook für Produktion

Wenn Ihr Produkt Nutzer auffordert, eine beliebige URL zum Scannen einzugeben, öffnen Sie Ihrem Server praktisch den Zugang zum gesamten Internet.

Beim Bau von ComplianceRadar wurde mir schnell klar: Rohe URL-Inputs sind kein nettes UX-Feature, sondern eine harte Sicherheitsgrenze.

Die Plattform läuft auf Next.js App Router, serverlosen API-Routen, Stripe und KI-basierten Analyse-Pipelines. Weil beliebige URLs akzeptiert werden, musste Security vom ersten Tag an Teil der Architektur sein.

SSRF-Risiko kontrollieren

Behandle jede eingereichte URL als potenziell feindlichen Input.

Outbound-Requests absichern

Protokoll-Checks, IP-Filter, Timeouts und Payload-Limits sind Pflicht.

Integrität von Zahlungsevents

Stripe-Signaturen am Raw-Body prüfen, bevor Features freigeschaltet werden.

Produktions-Stack im Kontext

  • Next.js (App Router)
  • Serverlose API-Routen
  • Stripe für Zahlungen
  • KI-basierte Analyse-Pipelines

1) Die SSRF-Gefahr: Vertraue URLs nie blind

Server-side Request Forgery (SSRF) entsteht, wenn Angreifer ein Backend dazu bringen, interne oder geschützte Netzwerkziele aufzurufen.

Statt einer regulären Ziel-URL senden Angreifer lokale oder Metadaten-Endpunkte und missbrauchen Ihren Server als Proxy.

  • http://localhost:3000/api/admin-delete-all
  • http://169.254.169.254/latest/meta-data/

Wenn Ihr Backend jedes Ziel ungeprüft abruft, ist die externe Firewall nicht länger die tatsächliche Schutzgrenze.

Um das zu verhindern, habe ich vor jedem Outbound-Request eine strikte Validierungs- und Sanitizing-Pipeline eingebaut.

Protokoll-Allowlist

  • Nur http:// und https:// zulassen
  • file://, ftp://, gopher://, data:// sofort ablehnen
  • Early fail, bevor irgendein Netzwerk-Call startet

Private IPs und geschützte Ranges blocken

Vor dem Fetch wird der Hostname aufgelöst. Zeigt die IP auf private oder sensible Bereiche, wird der Request sofort abgebrochen:

  • 127.0.0.0/8
  • 10.0.0.0/8
  • 192.168.0.0/16 und 172.16.0.0/12
  • 169.254.0.0/16 (Cloud-Metadaten-Endpunkte)
  • Alle localhost-äquivalenten internen Ziele

Timeouts und Payload-Limits

Jeder Outbound-Request läuft mit 10-Sekunden-AbortController-Timeout und Größenlimits, damit langsame Antworten oder riesige Downloads keine DoS-Angriffsfläche werden.

2) Umsatz schützen: Stripe-Webhooks härten

Nachdem die Scan-Engine abgesichert war, lag der nächste kritische Fokus auf dem Zahlungsfluss.

Wenn ein Nutzer bezahlt, sendet Stripe ein Event an /api/webhooks/stripe. Ein häufiger Anfängerfehler ist, das eingehende JSON direkt zu vertrauen und Premium sofort freizuschalten.

Das ist unsicher. Jeder kann einen POST auf diesen Endpoint schicken. Vertrauenswürdig ist nur ein Payload, der die Stripe-Signaturprüfung besteht.

  • stripe-signature
  • const body = await req.text()

Im Next.js App Router ist entscheidend, zuerst den Rohtext mit req.text() zu lesen und ihn erst anschließend weiterzuverarbeiten. Stripe signiert die exakten Rohbytes; vorheriges JSON-Parsing lässt die Verifikation fehlschlagen.

Referenz-Implementierung

Minimales Muster zur Webhook-Verifikation im Next.js App Router.

import { headers } from "next/headers";
import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export async function POST(req: Request) {
  const body = await req.text();
  const signature = headers().get("stripe-signature");

  if (!signature) return new Response("Unauthorized", { status: 400 });

  try {
    stripe.webhooks.constructEvent(body, signature, process.env.STRIPE_WEBHOOK_SECRET!);
  } catch {
    return new Response("Unauthorized", { status: 400 });
  }

  // Handle verified event
  return new Response("ok");
}

Security ist Architektur, nicht Checkbox

SSRF-Schutz hält die Scan-Engine von interner Infrastruktur und Cloud-Metadatendiensten getrennt.

Die Verifikation der Stripe-Signatur schützt Billing-Logik und Feature-Freischaltung vor gefälschten Zahlungsevents.

Ein großer Teil von produktionsreifer Software ist unsichtbar. Es ist der Code, der teure Ausfälle verhindert, bevor sie passieren.

Threat-Model-Checkliste (Ja/Nein)

Kurzer Selbstcheck, bevor Sie Ihr SaaS als produktionsreif bezeichnen:

  • 01Protokoll-Whitelist: Blockiert Ihre Anwendung alle Nicht-HTTP/HTTPS-Schemata wie file:// oder ftp:// konsequent bei Nutzereingaben?
  • 02Private-IP-Blocking: Werden eingereichte Domains aufgelöst und interne IP-Bereiche wie 127.x.x.x oder 169.254.x.x vor dem Abruf blockiert?
  • 03Outbound-Constraints: Sind alle serverseitigen Fetch-Requests in einen AbortController mit strikten Timeouts und Payload-Limits eingebettet?
  • 04Webhook-Integrität: Werden Stripe-Webhook-Signaturen anhand des Rohtexts (req.text()) verifiziert, bevor das JSON geparst wird?
  • 05Secret-Management: Liegen Webhook-Signing-Secrets und API-Keys sicher serverseitig und niemals mit NEXT_PUBLIC_-Präfix?

Wenn Sie das Projekt hinter diesen Entscheidungen prüfen möchten, sehen Sie sich ComplianceRadar an.

Öffentliches Produkt: complianceradar.dev

Wenn Sie gerade ein SaaS entwickeln, prüfen Sie URL-Eingaben und Webhook-Endpunkte besser vor dem ersten Sicherheitsvorfall.