Pourquoi une requête GET ne devrait-elle pas modifier les données sur le serveur?

109

Sur Internet, je vois les conseils suivants:

GET ne doit jamais modifier les données sur le serveur. Utilisez une requête POST pour cela.

Quelle est la base de cette idée?

Si je crée un service php qui insère des données dans la base de données et les transmet dans la chaîne de requête GET, pourquoi est-ce erroné? (J'utilise des instructions préparées pour prendre en charge l'injection SQL). Une demande POST est-elle en quelque sorte plus sécurisée?

Ou y a-t-il une raison historique à cela? Si oui, quelle est la validité de ce conseil aujourd'hui?

Devdatta Tengshe
la source
Merci d'avoir posé cette question, et merci @Oded pour sa réponse bien formulée. J'ai toujours eu besoin d'une référence pour envoyer les personnes qui posent cette question vers :)
Benjamin Gruenbaum
Voir aussi HTTP PUT - stackoverflow.com/questions/630453/put-vs-post-in-rest (avec des notes sur le fait d'être idempotent)
Bratch
2
@JoachimSauer Alors que GET les aurait sauvés du robot, le problème fondamental était le manque d'authentification. N'importe quel script aurait pu les envoyer dans l'oubli.
CodesInChaos

Réponses:

186

Ce n'est pas un conseil.

A GETest défini de cette manière dans le protocole HTTP . Il est supposé être idempotent et sûr .

Quant à pourquoi - un GETpeut être mis en cache et dans un navigateur, actualisé. Encore et encore et encore.

Cela signifie que si vous GETreproduisez la même chose , vous l'insérerez à nouveau dans votre base de données .

Considérez ce que cela signifie si le GETdevient un lien et que le moteur de recherche l'explore. Vous aurez votre base de données pleine de données en double.

Je suggère également de lire les URI, l’adressabilité et l’utilisation de HTTP GET et POST .


Il existe également un problème de prélecture de lien dans certains navigateurs: ils effectueront un appel pour rechercher des liens, même si cela n’a pas été indiqué par l’auteur de la page.

Si, par exemple, votre déconnexion est derrière un "GET", lié à chaque page de votre site, les utilisateurs peuvent se déconnecter simplement en raison de ce comportement.

Oded
la source
35
Beaucoup, beaucoup, beaucoup d'outils, utilitaires, robots d'exploration de sites Web et autres choses, supposent que GETce ne sera jamais une action destructrice (à juste titre, puisque c'est spécifié de cette façon). Si vous cassez maintenant votre application en violant cette spécification, vous garderez les deux parties de votre application.
Joachim Sauer
7
@NimChimpsky: il est changé par un GET. Ce conseil est tout simplement faux. Coffre-fort signifie que l'utilisateur ne peut pas être tenu responsable des effets secondaires, pas qu'il ne puisse en exister. Sinon, vous ne pourriez pas avoir de fichiers journaux pour votre serveur, ce qui serait absurde! Ceci est expliqué clairement dans la section 9.1.1 de la RFC2616.
Jörg W Mittag
8
@ JörgWMittag: Je ne dirais pas "tout simplement faux", je dirais "parfaitement formulé". L’EEG ne devrait pas avoir de changement, c’est son objectif. Bien sûr, vous êtes autorisé à compter, vous connecter et observer une requête GET. Mais cela ne devrait pas modifier vos données commerciales réelles.
Joachim Sauer
23
@NimChimpsky A GETne devrait pas changer la ressource demandée par le GET, mais cela ne veut pas dire "rien sur le serveur ne devrait changer". Bien sûr, des éléments tels que les journaux, les compteurs et les autres états du serveur peuvent changer lors de toute demande.
Eric King
9
Il y a quelques années, Google a publié un module complémentaire de navigateur (iirc) permettant de pré-récupérer des pages via des liens. Cela se produisait également sur certains panneaux de contrôle mal conçus: les URL provoqueraient l'écriture, voire la suppression d'un enregistrement, voire de la suppression sur le serveur (think post? Action = delete). Cela entraînait l'exécution d'actions à l'insu de l'utilisateur. Pour cette raison, Google a abandonné cet addon, iirc, même si le fabricant de l'application Web en était responsable pour avoir utilisé GET pour changer d'état.
Cthulhu
24

Chaque verbe HTTP a sa propre responsabilité. Par exemple GET, tel que défini par RFC

signifie récupérer n'importe quelle information (sous la forme d'une entité) qui est identifiée par l'URI de demande.

POSTd'autre part, signifie insérer ou plus formellement

La méthode POST est utilisée pour demander au serveur d'origine d'accepter l'
entité incluse dans la demande en tant que nouveau subordonné de la ressource
identifiée par l'URI de demande dans la ligne de demande.

Raisons pour le garder de cette façon:

  • C'est très simple et fonctionne à l'échelle mondiale d'Internet depuis 1991
  • S'en tenir au principe de responsabilité unique
  • D'autres parties ont l'habitude GETde jouer le rôle de moyens de récupération d'informations et d'exploration de données
  • GET est supposé être une opération sûre qui ne modifie jamais l'état de la ressource.
  • Considérations de sécurité, GETest effectivement une lecture , alors qu’elle POSTest effectivement une écriture
  • GET est mis en cache par les navigateurs, les nœuds du réseau, les fournisseurs de services Internet.
  • À moins que le contenu ne soit modifié, GETla même URL doit renvoyer les mêmes résultats à tous les utilisateurs, sans quoi vous n'aurez aucune confiance dans le résultat renvoyé.

Pour être complet et simplement imposer l'utilisation correcte (source) :

  • GETles paramètres sont transmis dans le cadre de l'URL, qui est par défaut d'une longueur petite et limitée de 256 caractères, certains serveurs prenant en charge plus de 4000 caractères. Si vous souhaitez insérer un long enregistrement, il n’existe aucun moyen légitime de transmettre ces données.
  • Si vous utilisez une connexion Secure, ̶ tels que tLS, ̶ URL ne reçoit pas Encrypted, ̶ D' où tous les paramètres ̶ ̶G̶E̶T̶̶ TRANSFÉRÉ PLAIN TExt sont. L'URL est actuellement crypté avec TLS, donc TLS va bien.
  • L'insertion de données binaires ou de caractères non-ASCII à l'aide GETn'est pas pratique
  • GET est ré-exécuté si un utilisateur appuie sur un bouton Précédent dans un navigateur
  • Certains robots plus anciens ne peuvent pas indexer les URL avec un ?signe à l'intérieur
oleksii
la source
1
Êtes-vous sûr que l'URL n'est pas chiffrée sur TLS? J'avais l'impression que les poignée de main SSL / TLS se produisent avant le transfert des en-têtes HTTP. C'est la raison pour laquelle l'hébergement virtuel de sites HTTPS sur une adresse IP unique est difficile. Est-ce que je me trompe?
Brandon
C'est vrai, je l'ai corrigé
oleksii
2
Les navigateurs modernes de @Brandon envoient le domaine hôte en clair dans le cadre de la négociation TLS (appelée indication du nom du serveur), afin d'autoriser l'hébergement de plusieurs domaines par adresse IP. La partie chemin / requête de l'URL est protégée par TLS. Il n'y a pas de différence entre GET et les autres verbes HTTP à cet égard.
CodesInChaos
10

EDIT: Avant, j’ai dit que le POST aide à vous protéger contre le CSRF mais c’est faux. Je n'y pensais pas correctement. Vous devez exiger un jeton masqué unique de la portée de la session dans toutes vos demandes de modification des données afin de vous protéger contre CSRF.

Au début de l'Internet, il existait des accélérateurs de navigateur. Ces programmes commenceraient à cliquer sur des liens sur une page pour mettre en cache le contenu. Google Web Accelerator était l'un de ces programmes. Cela pourrait causer des dégâts sur une application qui apporte des modifications lorsqu'un lien est cliqué. Je supposerais qu'il y a encore des personnes qui utilisent un logiciel d'accélérateur.

Les serveurs proxy et les navigateurs vont mettre en cache les requêtes GET. Ainsi, lorsque l'utilisateur accède à la page, il peut ne pas envoyer la requête à votre application. Il pense donc avoir pris une mesure, mais ce n'est pas le cas.

Sarel Botha
la source
1
CSRF est également possible avec GET et POST. Par exemple, l'attaquant peut inclure un formulaire de soumission automatique sur son site afin de déclencher une demande POST. L'approche standard pour empêcher CSRF inclut explicitement une valeur inconnue de l'attaquant dans la demande (contrairement aux en-têtes de cookie implicites).
CodesInChaos
8

Si je crée un service php qui insère des données dans la base de données et les transmet dans la chaîne de requête GET, pourquoi est-ce erroné?

La réponse la plus simple est "parce que ce n'est pas ce que GETsignifie".

Utiliser GETpour transmettre des données pour une mise à jour revient à écrire une lettre d'amour et à l'envoyer dans une enveloppe portant la mention "OFFRE SPÉCIALE - AGISSEZ MAINTENANT!" Dans les deux cas, vous ne devriez pas être surpris que le destinataire et / ou les intermédiaires traitent mal votre message .

Nathan Long
la source
5

Pour vos opérations CRUD dans une application centrée sur la base de données, utilisez le schéma suivant:

Utiliser HTTP GET pour les opérations de lecture (SQL SELECT)

Utiliser HTTP PUT pour les opérations de mise à jour (SQL UPDATE)

Utiliser HTTP POST pour créer des opérations (SQL INSERT)

Utiliser HTTP DELETE pour les opérations de suppression (SQL DELETE)


la source
3
Put vs post n'est pas comme vous le dites. Put est pour lorsque le client est en train de modifier la ressource à l'emplacement exact donné. Pour un message, le serveur décide en dernier lieu de l’URI exact de la ressource.
Andy
HTTP PUT ne ressemble-t-il pas davantage à SQL DELETE and INSERT qu'à UPDATE? SQL UPDATE peut également mettre à jour plusieurs enregistrements à la fois, mais HTTP PUT ne mettra à jour qu'une seule chose.
Backwards_Dave
0

GET ne doit jamais modifier les données sur le serveur. Utilisez une requête POST pour cela.

Ce conseil, et toutes les réponses ici sont fausses. Évidemment, je suis trop dramatique, les autres réponses sont excellentes, mais je crois que le conseil exact devrait être donné comme suit:

Un GET doit rarement modifier les données sur le serveur - utilisez une demande POST pour cela.

Dire «jamais» est trop extrême, et bien que les autres réponses ici expliquent avec précision pourquoi vous devriez le faire «rarement», il existe des scénarios dans lesquels il est parfaitement raisonnable de modifier les données avec une méthode GET. Un exemple est un lien de vérification de courrier électronique à usage unique. Généralement, ces liens contiennent un GUID qui, lorsqu’on y a accès, devra modifier les données. Si elles sont correctement implémentées, les requêtes GET identiques suivantes seront ignorées.

Il s’agit bien évidemment d’un cas extrême, mais il convient de le noter.

TTT
la source
3
Que se passe-t-il si votre client de messagerie décide de récupérer le lien sans que vous ne cliquiez dessus? Par exemple, parce qu'il veut le scanner pour les logiciels malveillants. L’approche appropriée pour les liens de désabonnement consiste à accéder à une page où l’utilisateur peut cliquer sur un bouton pour se désabonner (le clic de ce bouton déclenche une demande POST).
CodesInChaos
@CodesInChaos - excellent point! Je suis d'accord avec toi. J'ai supprimé l'exemple de désinscription et laissé la vérification du courrier électronique comme unique exemple. Il se peut qu’en dehors de la vérification des e-mails, une procédure GET ait un sens, mais je n’en ai aucune idée pour le moment.
TTT
Le problème des effets secondaires de GET s’applique également à la confirmation par courrier électronique. Maintenant, le client qui suit le lien confirmera un compte créé par une autre personne à l’aide de votre courrier électronique, lui permettant de vous imiter.
CodesInChaos
@CodesInChaos - c'est un étirement. L'emprunt d'identité dont vous parlez proviendrait du même nom d'utilisateur ou du même nom public, et non de la même adresse électronique, ce qui peut arriver quelle que soit l'adresse électronique utilisée (généralement, seul le serveur connaît l'adresse électronique du titulaire du compte). En outre, il serait inutile de créer un compte avec l'adresse e-mail de quelqu'un d'autre. Comment cela pourrait-il les aider? Ils ne pouvaient pas contrôler leur propre compte.
TTT