Warum brauchen GET-Endpunkte, die Daten verändern, eine Schreibfreigabe?
GET-Endpunkte, die Daten verändern, laden zu Wiederholungen, Vorschauen und versehentlichen Aktionen ein. Finden Sie versteckte Schreibvorgänge, gestalten Sie Verträge neu und verlangen Sie vor dem Senden eine Freigabe.

Ein GET-Endpunkt, der den Zustand verändert, ist eine Schreibaktion in der falschen Uniform. Die Gefahr ist nicht theoretisch. Browser, Crawler, API-Clients, Monitoring-Tools, Link-Vorschaudienste, Caches und Agents stellen zusätzliche GET-Anfragen, weil das Protokoll ihnen sagt, dass dies sicher ist. Wenn Ihr Endpunkt einen Job abbricht, ein Token rotiert, eine Nachricht versendet oder einen Datensatz verändert, können diese zusätzlichen Anfragen zu Aktionen in der Produktion werden.
Teams entdecken solche Routen oft nach einem seltsamen Vorfall und flicken dann den einzelnen Endpunkt, der Probleme verursacht hat. Das greift zu kurz. Sie müssen jeden leseähnlichen Aufruf finden, der etwas verändert, die Auswirkung nach ihren Folgen einordnen und ihn hinter dieselbe Autorisierungs- und Audit-Grenze stellen wie eine ausdrückliche Schreibaktion. Das Verb zu ändern ist wichtig, aber nur ein Teil der Reparatur.
Sichere HTTP-Methoden beschreiben die angeforderte Semantik
GET-Endpunkte, die Daten verändern, verletzen das Versprechen hinter der Methode, selbst wenn ihre Autoren praktische Gründe hatten, GET zu wählen. RFC 9110 definiert GET als sichere Methode und erklärt, dass eine sichere Anfrage den Server nicht auffordert, den Zustand zu ändern. Der RFC erlaubt beiläufige Effekte wie Protokollierung und Abrechnung, weil der Client diese Effekte nicht angefordert hat. Er entschuldigt keine Route, deren beabsichtigte Aufgabe eine Änderung ist.
Diese Unterscheidung entlarvt eine häufige Ausrede: „Der Server muss last_seen aktualisieren, wenn er das Element liest.“ Wenn der Client ein Element abrufen möchte und der Dienst einen internen Zugriffszeitstempel aktualisiert, kann das beiläufig sein. Wenn der Client ein Element abrufen möchte und der Dienst eine Rechnung als bezahlt markiert, einen Export erstellt, ein Token verbraucht oder einen Workflow weiterführt, ist die Änderung der angeforderte Vorgang. Nennen Sie ihn eine Schreibaktion.
RFC 9110 liefert auch den praktischen Grund, warum das wichtig ist. User-Agents dürfen sichere Methoden automatisieren. Ein Browser kann eine Seite abrufen, um eine Vorschau zu erstellen. Ein Crawler kann einem Link folgen. Eine Client-Bibliothek kann nach Verlust der Antwort erneut versuchen. Die Protokollsemantik erlaubt diesen Akteuren genau dieses Verhalten. Ihr Server kann sich nicht darauf verlassen, dass jeder Aufrufer seine undokumentierte Ausnahme gelesen hat.
Verwechseln Sie sicher nicht mit idempotent. Ein DELETE kann idempotent sein, weil die Ressource nach einer Wiederholung weiterhin gelöscht ist, und bleibt dennoch unsicher, weil der erste Aufruf den Zustand ändert. Ein GET, das bei jeder Anfrage einen Zähler erhöht, könnte nur im engen Sinn idempotent sein, wenn es nach einem Grenzwert aufhört, ist aber weiterhin unsicher, weil sein Zweck den Zustand verändert. Diese Begriffe beantworten unterschiedliche Fragen:
- Sicher fragt, ob der Aufrufer eine Zustandsänderung angefordert hat.
- Idempotent fragt, ob die Wiederholung derselben Anfrage denselben beabsichtigten Effekt hat.
- Cachebar fragt, ob ein Vermittler eine Antwort wiederverwenden darf.
Wenn ein Team diese Begriffe vermischt, führt es oft einen Schutz gegen Wiederholungen ein und hält das Problem für gelöst. Das Verhindern von Duplikaten hilft. Es hält einen Link-Scanner nicht davon ab, die erste zerstörerische Aktion auszuführen.
Nach Folgen suchen, nicht nach verdächtigen Routennamen
Versteckte Änderungen finden Sie, indem Sie verfolgen, was eine Route auslöst, statt ihrem Namen oder Verb zu vertrauen. Routen mit Namen wie getReport und view können Arbeit einreihen. Routen namens reset können völlig harmlos sein, wenn sie ein Formular zurückgeben. Erstellen Sie Ihr Inventar aus Laufzeitbelegen und Codepfaden zusammen.
Beginnen Sie mit jedem für GET und HEAD registrierten Handler. Verfolgen Sie bei jedem Handler direkte Schreibvorgänge und Übergaben: Datenbanktransaktionen, Queue-Publishing, Cache-Invalidierung mit fachlicher Bedeutung, E-Mail- oder Chat-Versand, Zahlungen, Änderungen an Anmeldedaten, Dateilöschung und ausgehende Aufrufe an einen anderen Dienst. Ein GET-Handler, der einen internen Dienst aufruft, kann im eigenen Repository sauber aussehen, während dieser interne Aufruf die Änderung ausführt. Folgen Sie ihm, bis Sie den endgültigen Effekt benennen können.
Diese einfache Suche findet viel alten Code:
rg -n 'GET|\.get\(|router\.get\(|app\.get\(' src
rg -n 'INSERT|UPDATE|DELETE|enqueue|publish|sendMail|charge|revoke|rotate' src
Die Form der Ausgabe ist weniger nützlich als der Prüfdatensatz, den Sie daraus erstellen. Geben Sie jedem Fund einen Endpunkt, Auslöser, endgültigen Effekt, betroffenes System und eine Liste der Aufrufer. Schreiben Sie in die Effektspalte nicht „aktualisiert Status“. Schreiben Sie „markiert Deployment d-481 als abgebrochen und sendet den Abbruch an den Scheduler“. Vage Einträge lassen einen Prüfer eine schwerwiegende Aktion leicht durchwinken.
Laufzeitdaten finden, was die Quellcodeprüfung übersieht. Senden Sie in einer Nicht-Produktionsumgebung repräsentative Anfragen mit einer Korrelations-ID. Fragen Sie dann Anwendungsprotokolle, Job-Tabellen, Protokolle ausgehender Aufrufe und Audit-Datensätze nach dieser ID ab. Wenn eine GET-Anfrage zu einer Nachricht, einer Zeilenänderung, einem Queue-Element oder einer externen Anfrage führt, zeichnen Sie die vollständige Kette auf. Eine Route kann über einen geplanten Worker erst einige Sekunden später etwas verändern, weshalb ein reines Anfrageprotokoll irreführend sein kann.
Achten Sie auf Änderungen, die Entwickler abtun, weil sie keine Schreibvorgänge in einer relationalen Datenbank sind. Das Erzeugen einer Einmal-Download-URL verbraucht eine Berechtigung. Das Starten eines Exports kann eine hohe Rechnung verursachen. Das Lesen einer Route zur „Einladungsannahme“ kann einen Benutzer zu einer Organisation hinzufügen. Der Aufruf eines Berichts-Endpunkts kann einen teuren Warehouse-Job wecken. Die Ressource, die Sie zurückgeben, kann schreibgeschützt sein, obwohl der Vorgang, der sie erzeugt hat, es nicht ist.
Alte APIs verstecken Schreibaktionen an vertrauten Stellen
Die schlimmsten alten Routen begannen meist als Abkürzungen für eine Seite für Menschen. Jemand machte einen administrativen Link leicht anklickbar, dann kopierte ein anderer Dienst die URL, dann wurde ein Skript davon abhängig, und die Abkürzung wurde zu einem API-Vertrag.
Links zur Bestätigung einer Passwortzurücksetzung sind ein klassischer Fall. Eine Route wie GET /reset/confirm?token=... wirkt praktisch, weil ein Browser sie öffnen kann. Wenn das Öffnen dieser URL das Token verbraucht und das Passwort ändert, können Mail-Scanner und Vorschau-Tools es zuerst verbrauchen. Das sichere Design verwendet GET, um einen Bestätigungsstatus anzuzeigen, ohne etwas zu verbrauchen, und POST, um die Bestätigung abzusenden. Die Seite kann eine kurzlebige serverseitige Referenz enthalten, doch die Schreibaktion erfolgt erst nach der ausdrücklichen Aktion.
Abmeldelinks brauchen mehr Sorgfalt, nicht weniger. E-Mail-Systeme und Datenschutzgesetze machen Abmeldungen mit einem Klick attraktiv, und einige Standards erwarten sie. Folgt ein Sicherheits-Scanner eines Postfachs einem solchen Link, kann der Empfänger ein Abonnement verlieren, ohne die Nachricht anzufassen. Nutzen Sie den Standardmechanismus über Header, wo er passt, verstehen Sie, wie das empfangende Ökosystem damit umgeht, und gestalten Sie das Verhalten des Endpunkts bewusst. Kopieren Sie kein allgemeines Muster „GET unsubscribe“ in eine unabhängige administrative API und nennen es Präzedenzfall.
Weitere häufige Fälle sind:
GET /jobs/123/retry, das bei jeder Aktualisierung eines Dashboards eine neue Ausführung erstellt.GET /deployments/123/rollback, das eine Monitoring-Prüfung beim Testen von Links aufrufen kann.GET /tokens/123/revoke, das eine Support-URL zu einer zerstörerischen Berechtigung macht.GET /invoices/123/send, das einen Vorschau-Bot zum E-Mail-Versender macht.GET /reports/monthly, das still einen kostspieligen Export startet, statt einen zurückzugeben.
Die verbreitete Empfehlung, „einfach einen geheimen Query-Parameter zu verlangen“, ist falsch. Query-Strings landen in Browserverläufen, Analytics, Serverprotokollen, Referrer-Headern in manchen Abläufen, Screenshots und kopierten Nachrichten. Wichtiger noch: Eine geheime URL bleibt eine GET-URL. Wer oder was auch immer sie erhält, kann die Aktion ohne Freigabegrenze auslösen.
Wiederholungen und Vorschauen vergrößern den Schadensradius
Ein einzelnes veränderndes GET erreicht mehr Empfänger, als sein Autor erwartet, denn automatisierte Aufrufer behandeln es als wiederholbar. Das erste Symptom wirkt oft zufällig: Ein Vorgang passiert zweimal, ein Konto ändert sich über Nacht oder ein Nutzer sieht eine Aktion, die er nicht ausgeführt hat. Die Anfrageprotokolle zeigen gültige Anmeldedaten, daher wird der Vorfall als Bedienfehler eingestuft. Dieses Etikett beendet die Untersuchung oft zu früh.
Betrachten Sie einen alten Endpunkt, der einen Remote-Build neu startet, wenn er GET /builds/77/retry empfängt. Ein Agent ruft die URL über einen Netzwerkpfad ab, der nach Annahme der Anfrage durch den Server in ein Timeout läuft. Der Agent tut, was viele HTTP-Clients tun, und versucht es erneut. Die ursprüngliche Anfrage hat Build 311 bereits eingereiht, die zweite reiht Build 312 ein. Anschließend lädt ein Dashboard einen Vorschau-Link im Aktivitätsfeed und reiht Build 313 ein. Der Handler kann jedes Mal 200 OK zurückgeben, daher verrät die Antwort nicht, dass der Vorgang dupliziert wurde.
Eine Weiterleitung kann eine weitere Überraschung bringen. Wenn eine alte GET-Aktion zu einer neuen Route weiterleitet und die neue Route weiterhin bei GET handelt, bewahrt die Weiterleitung die unsichere Semantik. Wenn die Weiterleitung die Methode auf eine Weise ändert, die der Client nicht erwartet, können Clients unterschiedlich fehlschlagen. Weiterleitungen helfen bei Migrationen, sie sind kein Ort, um Änderungen an Autorisierung oder Methodensemantik zu verstecken.
Caches machen den Fehler noch seltsamer. Ein gemeinsam genutzter Cache sollte eine Antwort auf ein veränderndes GET nicht ohne ausdrückliche Anweisung speichern, doch Systeme machen Fehler und Entwickler setzen Cache-Header mechanisch. Auch ohne gespeicherte Cache-Antwort kann ein Prefetcher die Anfrage stellen, bevor der Nutzer sich zur Aktion entschließt. Bauen Sie Sicherheit nicht auf der Hoffnung auf, dass jeder Vermittler Ihre private Absicht beachtet.
Die Reparatur beginnt an der Grenze. Ein Vorgang, der ein Remote-System verändern kann, braucht eine ausdrückliche Aktionsanfrage, bevor der HTTP-Client sie sendet. Der Aufrufer sollte einen klaren Aktionsnamen, das Ziel und die Folge sehen. Ein Timeout nach dem Senden ist dann eine ungewisse Schreibaktion, die der Aufrufer über eine Statusabfrage oder einen Idempotenzschlüssel behandelt, statt sie blind zu wiederholen.
Aktionen brauchen einen schreibähnlichen Vertrag
Ein reparierter Endpunkt sollte die Änderung in URI, Methode, Anfragekörper, Antwort und Dokumentation sichtbar machen. Sie brauchen keine REST-Debatte voller Substantive, um das gut umzusetzen. Sie brauchen einen Vertrag, der verhindert, dass Aufrufer eine Aktion mit einem Abruf verwechseln.
Verwenden Sie beim Build-Beispiel einen POST-Aktionsendpunkt und akzeptieren Sie einen Idempotenzschlüssel. Der Endpunkt sollte eine Ressource zurückgeben, die die neue Ausführung identifiziert, statt einer allgemeinen Erfolgsmeldung.
POST /v1/builds/77/retries HTTP/1.1
Idempotency-Key: 9ef8b462-97bf-4ca3-bb8b-4396a60ed9ae
Content-Type: application/json
{"reason":"retry after failed dependency download"}
HTTP/1.1 201 Created
Content-Type: application/json
Location: /v1/builds/311
{"id":"311","source_build":"77","state":"queued"}
Speichern Sie den Idempotenzschlüssel zusammen mit dem authentifizierten Prinzipal, Aktionstyp, Ziel und Anfragedigest. Sendet derselbe Aufrufer denselben Schlüssel und dieselbe Anfrage erneut, geben Sie das ursprüngliche Ergebnis zurück. Verwendet er den Schlüssel mit einem anderen Body oder Ziel wieder, geben Sie einen Konflikt zurück. Ein global gemeinsamer Schlüsseleintrag kann einen Mandanten mit einem anderen kollidieren lassen, während ein Schlüssel, der den Anfragekörper ignoriert, einen Copy-and-paste-Fehler zur falschen Aktion machen kann.
Verwenden Sie PUT oder PATCH, wenn die Anfrage den gewünschten Zustand der Ressource beschreibt. PATCH /v1/deployments/77 mit {"paused":true} kann sinnvoll sein, wenn die Ressource dieses Feld besitzt. POST /v1/deployments/77/rollback beschreibt besser einen Befehl mit neuer Ausführung, Audit-Trail und möglicherweise asynchronem Ergebnis. Zwängen Sie einen Befehl nicht in PATCH, nur um jemandes Styleguide zu erfüllen.
Geben Sie genug Zustand zurück, damit ein Aufrufer sich von Unklarheit erholen kann. Wenn eine Aktion asynchron läuft, geben Sie eine Operations-ID zurück und stellen Sie einen GET-Endpunkt bereit, der nur ihren Fortschritt liest. Das GET kann dann wiederholt, abgefragt, gemäß seinen Antwort-Headern zwischengespeichert und in einem Browser geöffnet werden, ohne die Welt zu verändern.
Die Freigabe gehört vor das Einfügen der Anmeldedaten
Eine Freigabe, nachdem eine HTTP-Anfrage den Rechner verlassen hat, ist Theater. Ein Remote-Dienst kann handeln, bevor der Client eine Antwort erhält, und eine Fehlerantwort beweist nicht, dass er nichts getan hat. Treffen Sie die Entscheidung dort, wo die Anfrage zusammengestellt wird, bevor Anmeldedaten angehängt werden und bevor Bytes den Prozess verlassen.
Das ist wichtig, wenn ein KI-Programmier-Agent eine API aufruft. Der Agent kann aus einer Tool-Beschreibung schließen, dass eine Route ein Lesevorgang ist, eine alte URL aus einem Repository kopieren oder einem Vorschlag in einem Ticket folgen. Hat er rohe Anmeldedaten, kann er den Aufruf ausführen, bevor ein Mensch den Endpunkt sieht. Ein Prompt, der das Modell zu Vorsicht auffordert, ist keine Autorisierungskontrolle.
Geben Sie der Freigabeschicht ein normalisiertes Aktionsmodell. Es sollte mindestens die HTTP-Methode, den Host, den Pfad, eine Zielkennung, sofern vorhanden, und eine kurze Beschreibung der Folge enthalten. Die Schicht sollte Aktionen anhand des Dienstvertrags einordnen, nicht nur anhand von method === "GET". Eine alte GET-Route, die revokeToken aufruft, muss denselben Freigabepfad durchlaufen wie POST /tokens/123/revoke, bis Sie sie entfernen.
Eine praktische Zuordnung kann so aussehen:
{
"method": "GET",
"url": "https://api.example.test/v1/tokens/tk_42/revoke",
"semantic_action": "revoke credential",
"target": "tk_42",
"approval": "required",
"reason": "legacy GET endpoint changes remote credential state"
}
Zeigen Sie einer freigebenden Person nicht nur einen Hostnamen und einen grünen Button. Der Hinweis sollte erklären, dass der Aufruf eine Anmeldedatenberechtigung widerruft, und das betroffene Ziel nennen. Kann Ihr System die semantische Aktion nicht bestimmen, behandeln Sie den Aufruf als nicht klassifiziert und verlangen eine Freigabe. Alle GET-Anfragen allein deshalb zu erlauben, weil sie GET-Anfragen sind, erzeugt denselben Fehler eine Ebene tiefer erneut.
Sallyports Autorisierung pro Sitzung und Anmeldedatenkontrollen pro Aufruf können an dieser Grenze für Agents eingesetzt werden, die seinen HTTP-Kanal nutzen. Die wichtige Architekturentscheidung ist unabhängig von der App: Der Tresorinhaber führt die Anfrage aus, während der Agent das Ergebnis statt des Geheimnisses erhält.
Lesezugriffe nützlich halten, Schreibaktionen schwer versehentlich auslösen
Das saubere Migrationsmuster bewahrt ein sicheres GET für die Erkundung und führt einen separaten Schreibendpunkt für die Aktion ein. Sie können eine benutzerfreundliche Seite, einen Statusendpunkt oder eine Dry-Run-Antwort behalten, ohne dass ein Abruf den Befehl ausführen kann.
Bei einem Berichtsgenerator kann GET /reports/monthly den zuletzt fertiggestellten Bericht und den aktuellen Erzeugungsstatus zurückgeben. POST /reports/monthly/runs startet eine neue Erzeugung. Bei einem Vorgang mit Anmeldedaten kann GET /tokens/tk_42 Metadaten zurückgeben, während POST /tokens/tk_42/revocations ein Widerrufsereignis erstellt. Das zusätzliche Pfadsegment ist weniger clever als ein Aktions-Query-Parameter, macht Protokolle, Clients und Prüfseiten aber deutlich klarer.
Ein Dry Run verdient einen präzisen Vertrag. POST /deployments/77/rollback?dry_run=true bleibt ein POST, weil der Aufrufer die Auswertung eines Befehls angefordert hat, auch wenn nichts festgeschrieben wird. Geben Sie die geplanten Ziele, erwarteten Vorbedingungen und alle ungelösten Werte zurück. Lassen Sie GET /rollback?preview=true nicht die Befehlsplanung ausführen, wenn diese Planung selbst Sperren setzt, Kapazität reserviert oder einen Anbieter mit beobachtbarer Wirkung kontaktiert.
Manche Teams versuchen, alte Integrationen zu bewahren, indem das alte GET eine HTML-Seite mit einem Formular zurückgibt, das automatisch ein POST absendet. Das verlagert das Risiko nur in den Browser. Verwenden Sie eine Seite, die eine echte Nutzerinteraktion erfordert und das POST mit den für die Anwendung passenden Same-Origin-Schutzmaßnahmen absichert. API-Clients sollten eine klare Deprecation-Antwort und einen Migrationstermin erhalten, kein Browserdokument, das sie nicht nutzen können.
Die Aufrufer testen, die nie um Erlaubnis fragen
Eine Route ist erst repariert, wenn Sie das automatisierte Verhalten testen, das sie unsicher gemacht hat. Unit-Tests, die bestätigen, dass ein Handler eine Dienstmethode aufruft, reichen nicht. Testen Sie die Route so, wie Browser, ein HTTP-Client bei Timeout, ein Crawler und ein Agent ihr begegnen würden.
Führen Sie für jede migrierte Aktion in einer isolierten Umgebung diese Prüfungen aus:
- Senden Sie das alte GET zweimal und bestätigen Sie, dass es keine zwei Aktionen erzeugen kann. Während einer Übergangsphase sollte es sicher fehlschlagen, nur einen Bestätigungsstatus anzeigen oder eine Deprecation-Antwort zurückgeben.
- Simulieren Sie einen Client, der die Antwort nach dem Senden verliert, und wiederholen Sie dann das POST mit demselben Idempotenzschlüssel. Bestätigen Sie, dass der Dienst die ursprüngliche Aktions-ID zurückgibt.
- Rufen Sie die sichere Status-URL wiederholt ab und bestätigen Sie, dass sie keine Jobs, Nachrichten, Buchungseinträge oder externen Aufrufe erzeugt.
- Versuchen Sie die Aktion mit einer abgelaufenen Freigabe oder widerrufenen Sitzung und bestätigen Sie, dass die Anfrage den Remote-Dienst nie erreicht.
- Prüfen Sie den Audit-Datensatz und verifizieren Sie, dass er die normalisierte Aktion benennt und nicht nur die Transportroute.
Nutzen Sie Fehlerinjektion an der unbequemen Stelle: nachdem der Server die Aktion festgeschrieben hat, aber bevor er eine Antwort sendet. Dort entdecken Teams, ob ihr Client blind wiederholt. Wenn die einzige Wiederherstellungsstrategie „Versuchen Sie es noch einmal“ lautet, liefert der Vertrag dem Aufrufer nicht genug Informationen.
Testen Sie auch Dokumentationsbeispiele. Ein curl-Befehl, der in einen Incident-Channel kopiert wird, wird zu einer operativen Schnittstelle. Wenn das Beispiel GET verwendet, weil es in eine Zeile passt, wird es jemand automatisieren. Machen Sie das Beispiel für sicheres Lesen und das Beispiel für die ausdrückliche Aktion sichtbar unterschiedlich.
Den Effekt ebenso auditieren wie die Route
Eine Audit-Zeile wie GET /v1/builds/77/retry 200 ist ein schlechter Nachweis. Sie erfasst eine Transporttatsache, versteckt aber das Geschäftsereignis. Bei einem Vorfall muss die untersuchende Person weiterhin rekonstruieren, ob der Aufruf einen Build gestartet, einen früheren wiederholt oder nur seinen Zustand zurückgegeben hat.
Zeichnen Sie beide Ebenen auf. Bewahren Sie die empfangene Methode und Route, weil altes Verhalten wichtig ist. Erfassen Sie daneben die semantische Aktion, das Ziel, den aufrufenden Prozess oder Prinzipal, die Freigabeentscheidung, die Identität der Anmeldedaten ohne geheimes Material, die Korrelations-ID und die Ergebnisreferenz. Bei einem asynchronen Befehl protokollieren Sie die Operations-ID oder die ID der entstandenen Ressource, damit spätere Ereignisse mit der ursprünglichen Anfrage verbunden werden.
Ein manipulationssicheres Protokoll ist nur dann nützlich, wenn Sie es prüfen können, nachdem Vertrauen fragwürdig geworden ist. Halten Sie den Prüfprozess getrennt vom normalen Lesepfad der Anwendung. Sallyport projiziert seine Sitzungs- und Aufrufjournale aus einem schreibblinden verschlüsselten, hash-verketteten Audit-Protokoll, und sp audit verify prüft diese Kette offline über Chiffretext. Diese Eigenschaft sollten Sie verlangen, wenn ein Agent berechtigt war, ein externes System zu beeinflussen.
Lassen Sie Audit-Aufbewahrung nicht zur Ausrede werden, Geheimnisse aufzuzeichnen. Anfragekörper enthalten oft Anmeldedaten, Tokens, personenbezogene Daten oder Befehlsargumente, die nicht in ein allgemeines Aktivitätsprotokoll gehören. Protokollieren Sie eine normalisierte Beschreibung und einen Digest, wenn Sie Integritätsnachweise brauchen. Speichern Sie sensible Daten nur dort, wo Zugriffskontrollen und Aufbewahrungsregeln sie tragen können.
Die Ausnahme entfernen, statt sie dauerhaft zu dokumentieren
Der Endzustand enthält keine verändernden GET-Routen, selbst wenn ein Freigabe-Gateway sie derzeit abfängt. Die Ausnahme am Leben zu halten, lädt einen neuen Client, eine kopierte URL oder ein künftiges Refactoring dazu ein, die Klassifikationstabelle zu umgehen. Die Kompatibilitätsschicht sollte einen Verantwortlichen, ein Inventar der Aufrufer und ein Datum haben, an dem sie die alte Form nicht mehr akzeptiert.
Beginnen Sie mit dem Endpunkt, der das unumkehrbarste Ergebnis verursachen kann. Ergänzen Sie einen ausdrücklichen POST-Vertrag, Idempotenzverhalten, eine Freigabeklassifikation und einen Audit-Datensatz auf Wirkungsebene. Machen Sie anschließend jeden alten GET-Aufruf beobachtbar. Wenn Sie die verbleibenden Aufrufer benennen können, migrieren Sie sie gezielt, statt eine versteckte Integration überraschend zu brechen.
Akzeptieren Sie „unser Client weiß es besser“ nicht als Sicherheitseigenschaft. Eine GET-Anfrage durchläuft Systeme, die dafür gebaut sind, sie zu wiederholen und zu untersuchen. Lassen Sie Ihre Schreibaktion wie eine Schreibaktion aussehen, bevor eines dieser Systeme beschließt zu helfen.
FAQ
Darf eine GET-Anfrage rechtlich Daten ändern?
Nein. GET ist als sichere HTTP-Methode definiert, weil die angeforderten Semantiken den Serverzustand nicht verändern sollen. Ein Server darf eine Anfrage zwar protokollieren oder intern einen Cache aktualisieren, aber ein GET, das löscht, neu startet, sendet, abrechnet oder einen Datensatz ändert, bricht den Vertrag, auf den sich Aufrufer verlassen.
Wie finde ich GET-Endpunkte mit Nebenwirkungen?
Beginnen Sie mit Routen namens retry, cancel, reset, resend, rotate, sync, export, confirm oder preview. Vergleichen Sie anschließend Anfrageprotokolle mit Datenbankschreibvorgängen, eingereihten Jobs, ausgehenden Nachrichten und Drittanbieteraufrufen, die direkt nach dem Ausführen dieser Routen stattfinden.
Muss ein GET-Endpunkt, der eine E-Mail versendet, freigegeben werden?
Behandeln Sie sie als Schreibaktion, wenn das gewünschte Ergebnis ein Konto, eine Ressource, einen Workflow, eine Berechtigung, einen Abrechnungsstatus, ein externes System oder die Zustellung einer Nachricht verändert. Das HTTP-Verb ist ein Hinweis auf die Absicht, kein Beweis dafür, dass der Vorgang harmlos ist.
Warum sind verändernde GET-Anfragen bei Wiederholungen gefährlich?
Sie können eine Anfrage nach einem Timeout wiederholen, einer Weiterleitung folgen, einen Link vorab abrufen, eine Seite aktualisieren oder eine Ressource beim Erstellen einer Vorschau laden. Ein Mensch glaubt vielleicht, nur einmal geklickt zu haben, während der Server zwei oder mehr Anfragen erhält.
Reicht Authentifizierung für eine zustandsändernde GET-Anfrage aus?
Nein. Authentifizierung beantwortet, wer einen Endpunkt aufrufen darf. Eine Freigabe beantwortet, ob diese konkrete Aktion jetzt stattfinden soll. An einen Agent angehängte langlebige Anmeldedaten machen eine unerwartete Zustandsänderung nicht akzeptabel.
Sollte ich für eine alte GET-Aktion POST, PUT oder PATCH verwenden?
Verwenden Sie einen POST-Aktionsendpunkt, wenn der Vorgang einen Befehl auslöst, etwa /jobs/{id}/cancel, und dokumentieren Sie sein Ergebnis. Verwenden Sie PUT oder PATCH, wenn der Aufrufer eine vollständige oder teilweise Repräsentation einer Ressource bereitstellt.
Kann ich die alte GET-Route aus Gründen der Abwärtskompatibilität behalten?
Behalten Sie die alte Route vorübergehend nur, wenn Sie ihre Aufrufer messen und migrieren können. Leiten Sie sie nur auf eine Seite ohne Zustandsänderung zur Bestätigung weiter, weisen Sie unsichere automatisierte Aufrufer ab oder geben Sie eine klare Deprecation-Antwort zurück, während Clients zum neuen Aktionsendpunkt wechseln.
Können Idempotenzschlüssel unsichere GET-Endpunkte sicher machen?
Ja, wenn jeder Versuch einen Idempotenzschlüssel mitführt und der Dienst das erste abgeschlossene Ergebnis für einen angemessenen Zeitraum speichert. Das schützt vor doppelter Zustellung, macht ein veränderndes GET aber nicht sicher für Crawler oder Vorschauen.
Was sollte ein Audit-Protokoll bei einer verändernden API-Anfrage erfassen?
Protokollieren Sie die normalisierte Aktion, das Ziel, die Identität des Aufrufers, die Autorisierungsentscheidung, das Ergebnis und eine Korrelations-ID. Zeichnen Sie auch die eingehende HTTP-Methode und Route auf, damit Untersuchende nachweisen können, dass eine alte leseähnliche Anfrage eine Schreibaktion ausgelöst hat.
Wie kann ein KI-Agent gefährliche API-Aufrufe freigeben, ohne Anmeldedaten zu sehen?
Platzieren Sie die Freigabegrenze, bevor der Client die HTTP-Anfrage sendet, denn der Remote-Dienst kann handeln, bevor eine Antwort zurückkommt. Sallyport kann das übernehmen, wenn ein Agent seinen HTTP-Kanal nutzt: Der Agent fordert eine Aktion an, während die App die Anmeldedaten einfügt und den Aufruf aufzeichnet.