Das Bot-Challenge-System von Cloudflare kann gewöhnliche HTML-Formular-Absendungen lautlos unterbinden und einen einfachen Klick auf eine Zahlung in eine Sackgasse für echte Nutzer verwandeln. Durch den Wechsel des Requests von einem nativen Navigation-POST zu einem Fetch-First-Flow lässt sich die User Experience wiederherstellen, ohne die Sicherheit zu beeinträchtigen.
Warum das Problem wichtig ist
Ein Entwickler veröffentlichte ein Zahlungsformular, das in jeder Testsuite, mit curl und auf dem lokalen Server funktionierte. Dasselbe Formular warf jedoch bei der Verwendung von Chrome durch einen Kunden nach dem ersten Klick einen Sicherheitsfehler und beim zweiten eine „timeout-or-duplicate“-Meldung. Das Scheitern erzwang drei Hotfix-Releases und einen ganzen Tag Debugging.
Die versteckte Edge
Das Formular ist Teil eines Open-Source-Astro-Pakets, das auf ein einfaches HTML <form>-Element setzt. Wenn der Nutzer auf Pay klickt, antwortet der Server mit einem 303-Redirect zu Stripe, und der Browser folgt dem Redirect ohne JavaScript. Websites nutzen dieses Muster als Fallback, wenn Skripte deaktiviert sind.
Cloudflare sitzt vor der Website und betreibt eine Bot-Detection-Engine. Bei gewöhnlichen GET-Requests kann sie eine interstitial Challenge (ein CAPTCHA oder einen JavaScript-Check) anzeigen. Sobald der Browser die Challenge bestanden hat, wird die Anfrage fortgesetzt.
Ein Navigation-POST kann jedoch nicht für eine Challenge angehalten und dann mit seinem Body intakt fortgesetzt werden. Die Edge verwirft die Anfrage und gibt einen 503-Status zurück, was im Browser zu einer leeren Seite oder einer generischen Fehlermeldung führt. Automatisierte Test-Browser, die denselben Fingerabdruck tragen, dem Cloudflare vertraut, lösen die Challenge nie aus – daher bleibt das Problem unsichtbar, bis ein echter Nutzer die Seite besucht.
Was die Logs enthüllten
Ein Live-Netzwerk-Trace einer Chrome-Session eines Nutzers zeigte zwei gegensätzliche Anfragen an denselben Endpunkt:
- Navigation POST → 503-Antwort, Tab hängt.
- fetch() POST → Anfrage abgeschlossen.
Beide Anfragen stammten aus derselben Origin, trugen dieselben Credentials und erfolgten zum selben Zeitpunkt. Der einzige Unterschied war die Transportmethode. Die Fetch-Anfrage umging den interstitial Flow, der Navigation-POSTs blockiert.
Wege, die ins Nichts führten
Der Entwickler versuchte eine Reihe von Korrekturen, die jedoch die eigentliche Ursache verfehlten:
- Erneuerung von Turnstile-Token, in der Annahme, sie seien abgelaufen.
- Whitelisting von IP-Bereichen, in der Annahme, die Blockierung sei standortbasiert.
- Deaktivierung von Erweiterungen, Löschen von Service Workern und Cookies.
Jede Änderung blieb ohne Wirkung, da der Fehler upstream an der Edge entstand und nicht im Client- oder Servercode.
Die pragmatische Lösung
Anstatt den Schutz von Cloudflare abzuschalten, wurde das Formular so umstrukturiert, dass es ein Fetch-First-Pattern nutzt:
- Sammeln der Formulardaten und Senden als JSON-Payload mittels
fetch(). - Verarbeiten der Serverantwort. Wenn der Server eine URL für das Payment-Gateway zurückgibt, wird
location.assign()aufgerufen, um per einfachem GET-Request dorthin zu navigieren.
Fetch-Anfragen lösen die interstitial Challenge nicht aus, sodass der POST den Origin-Server erreicht. Der anschließende GET-Redirect kann jede Challenge sicher passieren, da GET-Bodies leer sind und nach dem Bestehen der Challenge durch den Nutzer einfach erneut ausgeführt werden können.
Risiken für Entwickler
- Nutzervertrauen: Ein Zahlungsformular, das lautlos fehlschlägt, untergräbt das Vertrauen und kann zu Umsatzverlusten führen.
- Wartungsaufwand: Der Vorfall erforderte drei Patch-Releases und einen vollen Tag Recherche.
- Blinde Flecken beim Testen: Sich ausschließlich auf interne Testumgebungen zu verlassen, kann dazu führen, dass Edge-Case-Fehler übersehen werden, die erst in der realen Welt auftreten.
Lehren für die gesamte Community
- Reale Browser instrumentieren. Wenn ein Problem nur bei echten Nutzern auftritt, erfassen Sie die Netzwerk-Logs dieser Sessions, anstatt sich auf automatisierte Testläufe zu verlassen.
- Die Edge als Teil des Stacks betrachten. Cloudflare sitzt zwischen Client und Server; sein Verhalten beeinflusst, wie Anfragen strukturiert sein müssen.
- Den richtigen Transport wählen. Navigation-POSTs und Fetch-POSTs nutzen an der Edge unterschiedliche Pfade. Entwerfen Sie APIs mit diesem Unterschied im Hinterkopf.
- Fehlerdetails offenlegen. Machen Sie die 503- oder „timeout-or-duplicate“-Meldungen in der UI sichtbar, damit Entwickler den genauen Fehlermodus erkennen können, ohne sich durch Logs wühlen zu müssen.
Worauf man als Nächstes achten sollte
Entwickler sollten alle formbasierten Workflows prüfen, die auf nativem POST-Navigation basieren, insbesondere wenn Cloudflare oder ähnliche CDN-Sicherheitsdienste vor der Website geschaltet sind. Das Hinzufügen eines leichtgewichtigen Fetch-Wrappers kann ähnliche Fehler verhindern. Monitoring-Tools, die von der Edge generierte Statuscodes erfassen, werden das Problem melden, bevor es die Kunden erreicht.
Fazit: Wenn die Bot-Challenges von Cloudflare aktiv sind, ist eine einfache HTML-Formularübermittlung anfällig für ein lautloses Scheitern. Das Umleiten des POST-Requests über fetch() und der Abschluss des Ablaufs mit einem GET-Redirect umgeht die Einschränkung des Edge-Servers, während die Sicherheit gewahrt bleibt. Betrachten Sie den Edge als Code, nicht nur als einen Netzwerk-Hop, und gestalten Sie Ihre Transports entsprechend.
