Perché una richiesta GET non dovrebbe modificare i dati sul server?


109

Su Internet, vedo i seguenti consigli:

Un GET non dovrebbe mai modificare i dati sul server, utilizzare una richiesta POST per questo

Qual è la base per questa idea?

Se creo un servizio php che inserisce i dati nel database e gli passo i parametri nella stringa di query GET, perché è sbagliato? (Sto usando istruzioni preparate, per occuparmi di SQL Injection). Una richiesta POST è in qualche modo più sicura?

O c'è qualche motivo storico per questo? In tal caso, quanto è valido questo consiglio oggi?




Grazie per aver posto questa domanda, e grazie @Oded per la risposta ben formulata, ho sempre avuto bisogno di un riferimento per inviare le persone che fanno questa domanda verso :)
Benjamin Gruenbaum

Vedi anche HTTP PUT - stackoverflow.com/questions/630453/put-vs-post-in-rest (con note sull'essere idempotenti)
Bratch

2
@JoachimSauer Mentre GET li avrebbe salvati dal crawler, il problema alla radice era la mancanza di autenticazione. Qualsiasi sceneggiatura per bambini avrebbe potuto anche postarli nell'oblio.
Codici InChaos

Risposte:


185

Questo non è un consiglio.

A GETè definito in questo modo nel protocollo HTTP . Dovrebbe essere idempotente e sicuro .

Per quanto riguarda il motivo: a GETpuò essere memorizzato nella cache e in un browser. Ancora e ancora e ancora.

Questo significa che se si fanno lo stesso GETancora una volta, si inserirà nel database di nuovo .

Considera cosa può significare se GETdiventa un collegamento e viene sottoposto a scansione da un motore di ricerca. Avrai il tuo database pieno di dati duplicati.

Suggerisco anche di leggere URI, indirizzabilità e l'uso di HTTP GET e POST .


C'è anche un problema con il prefetching dei link in alcuni browser: effettueranno una chiamata per precaricare i link, anche se non indicato dall'autore della pagina.

Se, ad esempio, il logout si trova dietro un "GET", collegato da ogni pagina del tuo sito, le persone possono disconnettersi solo a causa di questo comportamento.


35
Molti, molti, molti strumenti, utilità, web crawler e altri dispositivi di supporto ipotizzano che GETnon sarà mai un'azione distruttiva (giustamente, poiché è specificato in questo modo). Se adesso rompi l'applicazione rompendo quella specifica, riuscirai a conservare entrambe le parti dell'applicazione.
Joachim Sauer

7
@NimChimpsky: viene cambiato da a GET. Questo consiglio è semplicemente sbagliato. Sicuro significa che l'utente non può essere ritenuto responsabile per gli effetti collaterali, non che non ci possano essere effetti collaterali. Altrimenti non potresti avere file di registro per il tuo server, il che sarebbe assurdo! Questo è spiegato abbastanza chiaramente nella sezione 9.1.1 di RFC2616.
Jörg W Mittag

8
@JörgWMittag: non direi "semplicemente sbagliato", direi "espresso in modo errato". Un GET non dovrebbe avere cambiamenti in quanto è obiettivo. Naturalmente puoi contare, accedere e osservare una richiesta GET. Ma non dovrebbe modificare i tuoi dati aziendali reali.
Joachim Sauer

23
@NimChimpsky A GETnon dovrebbe cambiare la risorsa richiesta da GET, ma ciò non significa che non dovrebbe cambiare nulla sul server. Ovviamente cose come log, contatori e altri stati del server possono cambiare durante qualsiasi richiesta.
Eric King

8
Qualche anno fa, Google ha rilasciato un componente aggiuntivo del browser (iirc) che precaricava le pagine tramite link. Ciò è accaduto anche su alcuni pannelli di controllo progettati in modo errato: gli URL causerebbero la scrittura o la cancellazione di un record o qualcosa sul server (pensate post? Action = delete). Ciò ha comportato l'esecuzione di azioni senza che l'utente lo sapesse. Google ha interrotto quel componente aggiuntivo per tale motivo, iirc, anche se era colpa del produttore di webapp per l'utilizzo di GET per cambiare stato.
Cthulhu,

24

Ogni verbo HTTP ha la propria responsabilità. Ad esempio GET, come definito da RFC

significa recuperare qualsiasi informazione (sotto forma di entità) identificata dall'URI di richiesta.

POSTd'altra parte, significa inserire o più formalmente

Il metodo POST viene utilizzato per richiedere che il server di origine accetti l'
entità racchiusa nella richiesta come nuovo subordinato della risorsa
identificata dall'URI di richiesta nella riga di richiesta

Ragioni per mantenerlo in questo modo:

  • È molto semplice e funziona su scala globale di Internet dal 1991
  • Attenersi al principio della responsabilità singola
  • Altre parti utilizzano GETcome mezzo per il recupero delle informazioni e il data mining
  • Si presume che GET sia un'operazione sicura che non modifica mai lo stato della risorsa
  • Considerazioni sulla sicurezza, GETè effettivamente una lettura , mentre POSTè effettivamente una scrittura
  • GET viene memorizzato nella cache da browser, nodi nella rete, provider di servizi Internet
  • A meno che il contenuto non cambi, GETlo stesso URL deve restituire gli stessi risultati a tutti gli utenti, altrimenti non avrai alcuna fiducia in merito al risultato restituito

Per completezza e solo per applicare l'uso corretto (fonte) :

  • GETi parametri vengono passati come parte dell'URL, che per impostazione predefinita è di lunghezza piccola e limitata di 256 caratteri, con alcuni server che supportano oltre 4000 caratteri. Se si desidera inserire un record lungo, non esiste un modo legittimo per passare questi dati
  • Quando si utilizza connessione protetta, ̶ come TLS, ̶ URL è non ottenere criptato, ̶ Quindi tutti i parametri del ̶ ̶G̶E̶T̶̶ sono trasferiti Testo normale. L'URL è effettivamente crittografato con TLS, quindi TLS va bene.
  • L'inserimento di dati binari o caratteri non ASCII mediante GETnon è pratico
  • GET viene rieseguito se un utente preme un pulsante Indietro in un browser
  • Alcuni crawler meno recenti potrebbero non indicizzare gli URL con un ?segno all'interno

1
Sei sicuro che l'URL non sia crittografato su TLS? Ho avuto l'impressione che gli handshake SSL / TLS si verifichino prima del trasferimento delle intestazioni HTTP. Questo è il motivo per cui i siti HTTPS di hosting virtuale su un singolo indirizzo IP sono difficili. Mi sbaglio?
Brandon,

Esatto, l'ho corretto
oleksii

2
@Brandon I browser moderni inviano il dominio host in chiaro come parte dell'handshake TLS (noto come indicazione del nome del server), per consentire l'hosting di più di un dominio per indirizzo IP. La parte percorso / query dell'URL è protetta da TLS. Non vi è alcuna differenza tra GET e altri verbi HTTP al riguardo.
Codici InChaos

9

EDIT: Prima, ho detto che POST ti aiuta a proteggerti dal CSRF ma questo è sbagliato. Non ci ho pensato bene. È necessario richiedere un token nascosto univoco nell'ambito della sessione in tutte le richieste per modificare i dati per proteggersi dal CSRF.

All'inizio di Internet c'erano acceleratori del browser. Questi programmi inizierebbero a fare clic sui collegamenti in una pagina per memorizzare nella cache il contenuto. Google Web Accelerator era uno di questi programmi. Ciò potrebbe causare il caos su un'applicazione che apporta modifiche quando si fa clic su un collegamento. Suppongo che ci siano ancora persone che usano il software acceleratore.

I server proxy e i browser memorizzeranno nella cache le richieste GET, quindi quando l'utente accede nuovamente alla pagina potrebbe non inviare la richiesta all'applicazione, quindi l'utente pensa di aver intrapreso un'azione, ma in realtà non l'ha fatto.


1
CSRF è ugualmente possibile con GET e POST. Ad esempio, l'attaccante può includere un modulo di invio automatico sul proprio sito per attivare una richiesta POST. L'approccio standard alla prevenzione del CSRF include esplicitamente un valore sconosciuto all'attaccante nella richiesta (a differenza delle intestazioni dei cookie implicitamente incluse).
CodesInCos

8

Se creo un servizio php che inserisce i dati nel database e gli passo i parametri nella stringa di query GET, perché è sbagliato?

La risposta più semplice è "perché non è questo che GETsignifica".

Utilizzare GETper passare i dati per un aggiornamento è come scrivere una lettera d'amore e inviarla in una busta contrassegnata "OFFERTA SPECIALE - AGGIUNGI ORA!" In entrambi i casi, non dovresti essere sorpreso che il destinatario e / o gli intermediari gestiscano male il tuo messaggio .


5

Per le tue operazioni CRUD in un'applicazione incentrata su database utilizzare il seguente schema:

Usa HTTP GET per operazioni di lettura (SQL SELECT)

Utilizza HTTP PUT per le operazioni di aggiornamento (SQL UPDATE)

Utilizza HTTP POST per creare operazioni (INSERT SQL)

Usa HTTP DELETE per le operazioni di eliminazione (SQL DELETE)


3
Put vs post non è come dici tu. Put è per quando il client sta modificando la risorsa nella posizione specificata. Per un post il server alla fine decide l'esatto Uri per la risorsa.
Andy,

HTTP PUT non è più simile a SQL DELETE e INSERT anziché a UPDATE? Anche SQL UPDATE può aggiornare più record contemporaneamente, ma HTTP PUT aggiornerà solo una cosa.
Backwards_Dave

0

Un GET non dovrebbe mai modificare i dati sul server, utilizzare una richiesta POST per questo

Quel consiglio e tutte le risposte qui sono sbagliate. Ovviamente sono eccessivamente drammatico, le altre risposte sono eccellenti, ma credo che il consiglio esatto debba essere dato come:

Un GET dovrebbe raramente modificare i dati sul server, utilizzare una richiesta POST per questo

Dire "mai" è troppo estremo, e sebbene le altre risposte qui spieghino accuratamente perché dovresti farlo "raramente", ci sono alcuni scenari in cui è perfettamente ragionevole cambiare i dati con un GET. Un esempio è un collegamento di verifica e-mail monouso. In genere questi collegamenti contengono un GUID che, una volta effettuato l'accesso, dovrà modificare i dati. Se implementate correttamente, le successive richieste GET identiche verranno ignorate.

Questo è ovviamente un caso limite, ma sicuramente vale la pena notare.


3
Cosa succede se il tuo client di posta decide di recuperare il link senza che tu faccia clic su di esso? Ad esempio perché vuole scansionarlo alla ricerca di malware. L'approccio corretto per i collegamenti di annullamento dell'iscrizione è quello di condurre a una pagina in cui l'utente può fare clic su un pulsante per annullare l'iscrizione (in cui il clic sul pulsante attiva una richiesta POST).
CodesInCos

@CodesInChaos - punto eccellente! Sono d'accordo con te. Ho rimosso l'esempio di annullamento dell'iscrizione e ho lasciato la verifica tramite e-mail come unico esempio. Potrebbero essercene altri oltre alla verifica tramite e-mail in cui un GET ha senso, ma al momento non riesco a pensarci.
TTT,

Il problema con GET che ha effetti collaterali si applica anche alla conferma via e-mail. Ora il client che segue il link confermerebbe un account creato da qualcun altro utilizzando la tua e-mail, consentendo loro di impersonare te.
Codici A Caos il

@CodesInChaos - quello è un tratto. La rappresentazione di cui parli verrebbe dallo stesso nome utente o nome personale pubblico, non dallo stesso indirizzo e-mail e ciò può accadere indipendentemente dall'indirizzo e-mail utilizzato (in genere solo il server conosce l'indirizzo e-mail del titolare dell'account). Inoltre, sarebbe inutile creare un account con l'indirizzo e-mail di qualcun altro. Come potrebbe aiutarli? Non potevano controllare il proprio account.
TTT,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.