Warum sollte eine GET-Anforderung keine Daten auf dem Server ändern?

109

Überall im Internet sehe ich folgende Ratschläge:

Ein GET sollte niemals Daten auf dem Server ändern - verwenden Sie dazu eine POST-Anfrage

Was ist die Basis für diese Idee?

Wenn ich einen PHP-Dienst erstelle, der Daten in die Datenbank einfügt, und diese Parameter in die GET-Abfragezeichenfolge übergebe, warum ist das falsch? (Ich benutze vorbereitete Anweisungen, um mich um SQL Injection zu kümmern). Ist eine POST-Anfrage in gewisser Weise sicherer?

Oder gibt es einen historischen Grund dafür? Wenn ja, wie gültig ist dieser Ratschlag heute?

Devdatta Tengshe
quelle
Danke, dass Sie diese Frage gestellt haben, und danke @Oded für die gut formulierte Antwort. Ich brauchte immer einen Verweis, um Leute zu schicken, die diese Frage stellen :)
Benjamin Gruenbaum
Siehe auch HTTP PUT - stackoverflow.com/questions/630453/put-vs-post-in-rest (mit Hinweisen zur Idempotenz)
Bratch
2
@JoachimSauer GET hätte sie zwar vom Crawler gespeichert, das Hauptproblem war jedoch die fehlende Authentifizierung. Jedes Drehbuchkind hätte sie auch in Vergessenheit geraten lassen können.
CodesInChaos

Antworten:

185

Dies ist kein Ratschlag.

A GETist auf diese Weise im HTTP-Protokoll definiert . Es soll idempotent und sicher sein .

Was den Grund GETbetrifft - a kann zwischengespeichert und in einem Browser aktualisiert werden. Immer wieder und wieder und wieder.

Dies bedeutet , dass wenn Sie das gleiche machen GETwieder, werden Sie in Ihre Datenbank einfügen wieder .

Überlegen Sie, was dies bedeuten kann, wenn der GETLink zu einem Link wird und von einer Suchmaschine gecrawlt wird. Sie haben Ihre Datenbank mit doppelten Daten gefüllt.

Ich empfehle außerdem, URIs, Adressierbarkeit und die Verwendung von HTTP GET und POST zu lesen .


Es gibt auch ein Problem beim Vorabrufen von Links in einigen Browsern - sie rufen vorab abgerufene Links auf, auch wenn dies nicht vom Seitenautor angegeben wurde.

Wenn sich Ihre Abmeldung beispielsweise hinter einem "GET" befindet, das von jeder Seite Ihrer Website aus verlinkt wird, können sich Personen aufgrund dieses Verhaltens abmelden.

Oded
quelle
35
Viele, viele, viele Tools, Dienstprogramme, Webcrawler und andere Dinge gehen davon aus, dass dies GETniemals eine destruktive Aktion sein wird (zu Recht, da dies so festgelegt ist). Wenn Sie jetzt Ihre Anwendung durch Verletzung dieser Spezifikation brechen, behalten Sie beide Teile Ihrer Anwendung bei.
Joachim Sauer
7
@NimChimpsky: es wird von a geändert GET. Dieser Rat ist einfach falsch. Sicher bedeutet, dass der Benutzer nicht für Nebenwirkungen zur Verantwortung gezogen werden kann, nicht dass es keine Nebenwirkungen geben kann. Andernfalls könnten Sie keine Protokolldateien für Ihren Server haben, was absurd wäre! Dies ist in Abschnitt 9.1.1 von RFC2616 recht deutlich dargestellt.
Jörg W Mittag
8
@ JörgWMittag: Ich würde nicht "einfach falsch" sagen, sondern "unperfekt formuliert". Ein GET sollte keine Änderung als Ziel haben. Natürlich dürfen Sie eine GET-Anfrage zählen, protokollieren und beobachten. Es sollte jedoch nicht Ihre tatsächlichen Geschäftsdaten ändern.
Joachim Sauer
23
@NimChimpsky A GETsollte die von der angeforderte Ressource nicht ändern GET, aber das bedeutet nicht, dass sich nichts auf dem Server ändern sollte. Natürlich können sich Dinge wie Protokolle, Leistungsindikatoren und andere Serverstatus während einer Anforderung ändern.
Eric King
8
Vor einigen Jahren hat Google ein Browser-Add-On (iirc) veröffentlicht, mit dem Seiten über Links vorab abgerufen werden können. Dies geschah auch auf einigen schlecht gestalteten Control Panels - die URLs führten dazu, dass ein Datensatz oder etwas auf dem Server geschrieben oder sogar gelöscht wurde (think post? Action = delete). Dies führte dazu, dass Aktionen ausgeführt wurden, ohne dass der Benutzer davon wusste. Google hat dieses Addon aus diesem Grund eingestellt, iirc, auch wenn es die Schuld des Webapp-Herstellers war, GETs zu verwenden, um den Status zu ändern.
Cthulhu
24

Jedes HTTP-Verb hat seine eigene Verantwortung. Zum Beispiel GETwie in RFC definiert

bedeutet das Abrufen aller Informationen (in Form einer Entität), die von der Anforderungs-URI identifiziert werden.

POSTbedeutet andererseits einfügen oder formeller

Die POST-Methode wird verwendet, um anzufordern, dass der Ursprungsserver
die in der Anforderung enthaltene Entität als neuen Untergebenen der
durch den Anforderungs-URI in der Anforderungszeile angegebenen Ressource akzeptiert

Gründe, es so zu halten:

  • Es ist sehr einfach und funktioniert seit 1991 im globalen Internet
  • Halten Sie sich an das Prinzip der einmaligen Verantwortung
  • Andere Parteien GETfungieren als Mittel zum Abrufen von Informationen und zum Data Mining
  • Es wird davon ausgegangen, dass GET eine sichere Operation ist, die den Status der Ressource niemals ändert
  • Sicherheitsüberlegungen GETsind effektiv ein Lesen , wohingegen POSTes effektiv ein Schreiben ist
  • GET wird von Browsern, Knoten im Netzwerk und Internetdienstanbietern zwischengespeichert
  • Sofern sich der Inhalt nicht ändert, GETmuss dieselbe URL für alle Benutzer dieselben Ergebnisse zurückgeben. Andernfalls haben Sie kein Vertrauen in das zurückgegebene Ergebnis

Der Vollständigkeit halber und nur zur Durchsetzung der korrekten Verwendung (Quelle) :

  • GETParameter werden als Teil der URL übergeben, die standardmäßig eine geringe und begrenzte Länge von 256 Zeichen aufweist. Einige Server unterstützen über 4000 Zeichen. Wenn Sie einen langen Datensatz einfügen möchten, gibt es keine legitime Möglichkeit, diese Daten weiterzugeben
  • Bei der Verwendung von sicheren Verbindung, ̶ wie TLS, ̶ URL ist SCHRITTE Verschlüsselte, ̶ daher alle Parameter ̶ ̶G̶E̶T̶̶ übertragen Klartext. Die URL ist aktuell mit TLS verschlüsselt, daher ist TLS in Ordnung.
  • Das Einfügen von Binärdaten oder Nicht-ASCII-Zeichen mit GETist nicht praktikabel
  • GET wird erneut ausgeführt, wenn ein Benutzer in einem Browser die Schaltfläche Zurück drückt
  • Einige ältere Crawler indizieren möglicherweise keine URLs mit einem darin enthaltenen ?Zeichen
oleksii
quelle
1
Sind Sie sicher, dass die URL über TLS unverschlüsselt ist? Ich hatte den Eindruck, dass die SSL / TLS-Handshakes auftreten, bevor die HTTP-Header übertragen werden. Dies ist der Grund, warum das virtuelle Hosten von HTTPS-Sites über eine einzelne IP-Adresse schwierig ist. Irre ich mich
Brandon
Das stimmt, ich habe es behoben
oleksii
2
@Brandon Moderne Browser senden die Host-Domain als Teil des TLS-Handshakes (als Servername bezeichnet) im Klartext, damit mehr als eine Domain pro IP-Adresse gehostet werden kann. Der Pfad- / Abfrageteil der URL ist durch TLS geschützt. In dieser Hinsicht gibt es keinen Unterschied zwischen GET und anderen HTTP-Verben.
CodesInChaos
9

EDIT: Vorher habe ich gesagt, dass POST Ihnen hilft, sich vor CSRF zu schützen, aber das ist falsch. Ich habe das nicht richtig durchdacht. Sie müssen in allen Ihren Anforderungen ein eindeutiges verstecktes Token für den Sitzungsbereich angeben, um Daten zum Schutz vor CSRF zu ändern.

In den frühen Tagen des Internets gab es Browser-Beschleuniger. Diese Programme würden anfangen, auf Links auf einer Seite zu klicken, um den Inhalt zwischenzuspeichern. Google Web Accelerator war eines dieser Programme. Dies kann zu Schäden an einer Anwendung führen, die Änderungen vornimmt, wenn auf einen Link geklickt wird. Ich würde davon ausgehen, dass es immer noch Leute gibt, die Accelerator-Software verwenden.

Proxyserver und Browser speichern GET-Anforderungen im Cache. Wenn der Benutzer erneut auf die Seite zugreift, wird die Anforderung möglicherweise nicht an Ihre Anwendung gesendet, sodass der Benutzer denkt, dass er eine Aktion ausgeführt hat, dies jedoch nicht der Fall ist.

Sarel Botha
quelle
1
CSRF ist mit GET und POST gleichermaßen möglich. Beispielsweise kann der Angreifer ein automatisch übermittelndes Formular an seiner Site einfügen, um eine POST-Anforderung auszulösen. Der Standardansatz zum Verhindern von CSRF umfasst explizit einen dem Angreifer unbekannten Wert in der Anforderung (im Gegensatz zu den implizit enthaltenen Cookie-Headern).
CodesInChaos
8

Wenn ich einen PHP-Dienst erstelle, der Daten in die Datenbank einfügt, und diese Parameter in die GET-Abfragezeichenfolge übergebe, warum ist das falsch?

Die einfachste Antwort ist "weil das nicht GETheißt".

Wenn Sie GETDaten für ein Update weitergeben, schreiben Sie einen Liebesbrief und senden ihn in einem Umschlag mit der Aufschrift "SONDERANGEBOT - JETZT HANDELN!". In beiden Fällen sollten Sie sich nicht wundern, wenn der Empfänger und / oder die Vermittler Ihre Nachricht falsch handhaben .

Nathan Long
quelle
5

Verwenden Sie für Ihre CRUD- Operationen in einer datenbankzentrierten Anwendung das folgende Schema:

Verwenden Sie HTTP GET für Leseoperationen (SQL SELECT)

Verwenden Sie HTTP PUT für Aktualisierungsvorgänge (SQL UPDATE)

HTTP POST für Erstellungsvorgänge verwenden (SQL INSERT)

Verwenden Sie HTTP DELETE für Löschvorgänge (SQL DELETE)


quelle
3
Put vs Post ist nicht so, wie Sie sagen. Put ist für den Fall vorgesehen, dass der Client die Ressource am genau angegebenen Ort ändert. Für einen Beitrag entscheidet der Server letztendlich über die genaue Uri der Ressource.
Andy
Ist HTTP PUT nicht eher ein SQL DELETE und INSERT als ein UPDATE? SQL UPDATE kann auch viele Datensätze gleichzeitig aktualisieren, HTTP PUT aktualisiert jedoch nur eines.
Backwards_Dave
0

Ein GET sollte niemals Daten auf dem Server ändern - verwenden Sie dazu eine POST-Anfrage

Dieser Rat und alle Antworten hier sind falsch. Natürlich bin ich zu dramatisch, die anderen Antworten sind ausgezeichnet, aber ich glaube, der genaue Rat sollte lauten:

Ein GET sollte selten Daten auf dem Server ändern - verwenden Sie dazu eine POST-Anfrage

"Nie" zu sagen ist zu extrem und obwohl die anderen Antworten hier genau erklären, warum Sie es "selten" tun sollten, gibt es einige Szenarien, in denen es durchaus sinnvoll ist, Daten mit einem GET zu ändern. Ein Beispiel ist ein E-Mail-Bestätigungslink zur einmaligen Verwendung. In der Regel enthalten diese Links eine GUID, über die beim Zugriff Daten geändert werden müssen. Bei korrekter Implementierung werden nachfolgende identische GET-Anforderungen ignoriert.

Dies ist offensichtlich ein Randfall, aber sicherlich erwähnenswert.

TTT
quelle
3
Was passiert, wenn Ihr Mailclient den Link abruft, ohne dass Sie darauf klicken? Zum Beispiel, weil es nach Malware suchen möchte. Der richtige Ansatz für das Abbestellen von Links besteht darin, zu einer Seite zu führen, auf der der Benutzer auf eine Schaltfläche zum Abbestellen klicken kann (wobei das Klicken auf die Schaltfläche eine POST-Anforderung auslöst).
CodesInChaos
@CodesInChaos - ausgezeichneter Punkt! Ich stimme mit Ihnen ein. Ich habe das Abmeldebeispiel entfernt und die E-Mail-Bestätigung als einziges Beispiel belassen. Es mag neben der E-Mail-Bestätigung noch andere geben, bei denen ein GET sinnvoll ist, aber mir fällt momentan keine ein.
TTT
Das Problem mit GET mit Nebenwirkungen gilt auch für die Bestätigung per E-Mail. Der Client, der dem Link folgt, bestätigt nun ein Konto, das mit Ihrer E-Mail-Adresse erstellt wurde, und ermöglicht es ihm, sich als Sie auszugeben.
CodesInChaos
@CodesInChaos - das ist eine Strecke. Die Identität, von der Sie sprechen, stammt von demselben Benutzernamen oder öffentlichen persönlichen Namen, nicht von derselben E-Mail-Adresse. Dies kann unabhängig von der verwendeten E-Mail-Adresse geschehen (normalerweise kennt nur der Server die E-Mail-Adresse des Kontoinhabers). Außerdem wäre es sinnlos, ein Konto mit der E-Mail-Adresse einer anderen Person zu erstellen. Wie könnte das ihnen helfen? Sie konnten ihren eigenen Account nicht kontrollieren.
TTT