web-dev-qa-db-fra.com

Quel est le problème avec l'utilisation de $ _REQUEST []?

J'ai vu un certain nombre de publications ici ne pas utiliser la variable $_REQUEST D'habitude je ne le fais pas, mais parfois c'est pratique. Qu'est ce qui ne va pas avec ça?

112
sprugman

Il n'y a absolument rien de mal à prendre des entrées à la fois de $_GET et de $_POST de manière combinée. En fait, c'est ce que vous voulez presque toujours faire:

  • pour une requête simple idempotente habituellement envoyée via GET, il est possible que la quantité de données souhaitée ne tienne pas dans une URL; elle a donc été mutée en une demande POST à la place.

  • pour une demande qui a un effet réel, vous devez vérifier qu'elle est soumise par la méthode POST. Mais la manière de le faire est de vérifier $_SERVER['REQUEST_METHOD'] de manière explicite, sans compter que $_POST soit vide pour un GET. Et de toute façon, si la méthode est POST, vous voudrez peut-être extraire certains paramètres de requête de l'URL.

Non, le problème avec $_REQUEST n'a rien à voir avec la fusion des paramètres GET et POST. C'est qu'il inclut également, par défaut, $_COOKIE. Et les cookies ne ressemblent vraiment pas du tout aux paramètres de soumission de formulaire: vous ne voulez presque jamais les traiter comme la même chose.

Si vous obtenez accidentellement un cookie sur votre site avec le même nom que l'un de vos paramètres de formulaire, les formulaires qui reposent sur ce paramètre cesseront mystérieusement de fonctionner correctement en raison des valeurs de cookie remplaçant les paramètres attendus. Ceci est très facile à faire si vous avez plusieurs applications sur le même site, et peut être très difficile à déboguer lorsque vous n'avez que quelques utilisateurs avec de vieux cookies que vous n'utilisez plus de traîner et de casser les formulaires de manière non -un autre peut se reproduire.

Vous pouvez modifier ce comportement dans l'ordre beaucoup plus logique GP (no C) avec request_order config dans PHP 5.3. Là où ce n'est pas possible, j'éviterais personnellement $_REQUEST et, si j'avais besoin d'un tableau combiné GET + POST, créez-le manuellement.

181
bobince

J'ai fouillé dans quelques publications sur PHP Internals et ai trouvé une discussion intéressante sur le sujet. Le fil de discussion initial portait sur autre chose, mais une remarque de Stefan Esser, un expert en sécurité (si non le ) du monde PHP a tourné la discussion vers le conséquences de l’utilisation de $ _REQUEST pour quelques publications.

Citer Stefan Esser sur PHP Internals

$ _REQUEST est l’une des plus grandes faiblesses de conception de PHP. Toute application utilisant $ _REQUEST est très probablement vulnérable aux problèmes de contrefaçon de demande intersite retardée. (Cela signifie fondamentalement que si, par exemple, un cookie nommé (age) existe, il écrasera toujours le contenu GET/POST et les requêtes non souhaitées seront donc exécutées.)

et dans un répondre plus tard au même fil

Il ne s'agit pas du fait que quelqu'un puisse forger GET, POST; Variables COOKIE. Il s'agit du fait que les COOKIE écraseront les données GET et POST dans REQUEST.

Par conséquent, je pourrais infecter votre navigateur avec un cookie indiquant, par exemple, action = logout et à partir de ce jour, vous ne pourrez plus utiliser l'application car REQUEST [action] sera déconnecté pour toujours (jusqu'à ce que vous supprimiez manuellement le cookie).

Et vous infecter avec un cookie est si simple ...
a) Je pourrais utiliser une vulve XSS dans n’importe quelle application sur un sous-domaine
b) Avez-vous déjà essayé de définir un cookie pour * .co.uk ou * .co.kr lorsque vous y possédez un seul domaine?
c) Autres domaines interdépendants de quelque manière que ce soit ...

Et si vous pensez que ce n’est pas un problème, je peux vous dire qu’il existe une possibilité simple de régler f.e. un cookie * .co.kr donnant lieu à plusieurs PHP versions ne renvoyant que des pages blanches. Imaginez: un seul cookie pour tuer toutes les PHP pages de * .co.kr

Et en définissant un identifiant de session illégal dans un cookie valide pour * .co.kr dans une variable appelée + PHPSESSID = illégale vous pouvez toujours utiliser DOS toutes les PHP applications. en Corée en utilisant PHP sessions ...

La discussion continue pour quelques autres publications et est intéressante à lire.


Comme vous pouvez le constater, le problème principal de $ _REQUEST n’est pas tant qu’il dispose de données provenant de $ _GET et de $ _POST, mais également de $ _COOKIE. D'autres membres de la liste ont suggéré de modifier l'ordre dans lequel $ _REQUEST est rempli, par exemple. remplissez-le d'abord avec $ _COOKIE, mais cela pourrait entraîner de nombreux autres problèmes potentiels, par exemple avec le traitement de la session .

Cependant, vous pouvez complètement omettre $ _COOKIES du $ _REQUEST global, afin qu’il ne soit écrasé par aucun autre tableau (en fait, vous pouvez le limiter à toute combinaison de son contenu standard, comme le manuel PHP sur le variable_order le paramètre ini nous dit:

variable_order Définit l'ordre d'analyse des variables EGPCS (Environment, Get, Post, Cookie et Server). Par exemple, si variables_order est défini sur "SP", alors PHP créera les superglobales $ _SERVER et $ _POST, mais ne créera pas $ _ENV, $ _GET et $ _COOKIE. Le réglage sur "" signifie qu'aucun superglobal ne sera défini.

Mais encore une fois, vous pouvez également envisager de ne pas utiliser $ _REQUEST complètement, simplement parce que, dans PHP, vous pouvez accéder à Environment, Obtenir, Publier, Cookie et Serveur dans leurs propres globaux et disposer d’un vecteur d’attaque de moins. Vous devez toujours effacer ces données, mais c'est une chose de moins à craindre.


Maintenant, vous vous demandez peut-être pourquoi $ _REQUEST existe après tout et pourquoi il n’est pas supprimé. Cette question a également été posée sur PHP Internals. Citant Rasmus Lerdorf à propos de Pourquoi $ _REQUEST existe-t-il? sur PHP Internals

Plus nous supprimons de choses de ce type, plus il devient difficile pour les utilisateurs de passer rapidement à des versions plus récentes, plus rapides et plus sûres de PHP. Cela provoque beaucoup plus de frustration pour tout le monde que quelques fonctionnalités "laides" héritées. S'il existe une raison technique, des performances ou une sécurité décentes, nous devons examiner la situation de près. Dans ce cas, la question que nous devrions examiner n’est pas de savoir si nous devons supprimer $ _REQUEST mais si nous devrions supprimer les données de cookies. De nombreuses configurations le font déjà, y compris toutes les miennes, et il existe une raison de sécurité valable qui justifie de ne pas inclure les cookies dans $ _REQUEST. La plupart des gens utilisent $ _REQUEST pour désigner GET ou POST, sans se rendre compte qu'il pourrait également contenir des cookies. De ce fait, les personnes mal intentionnées pourraient potentiellement effectuer des manœuvres d'injection de cookies et casser des applications naïves.

Quoi qu’il en soit, espérons que cela jettera un peu de lumière.

72
Gordon

$_REQUEST fait référence à toutes sortes de requêtes (GET, POST etc ..). C'est parfois utile, mais il est généralement préférable de spécifier la méthode exacte ($ _GET, $ _POST, etc.).

10
Luca Matteis

Les requêtes GET doivent être idempotentes et POST les requêtes ne le sont généralement pas. Cela signifie que les données dans $_GET et $_POST doivent généralement être utilisées de différentes manières.

Si votre application utilise les données de $_REQUEST, elle se comportera de la même manière pour les requêtes GET et POST, ce qui violerait la capacité de base de GET.

8
Ben James

$_REQUEST est généralement considéré comme dangereux pour la même raison que des transformations de données simples à moyennement complexes sont souvent effectuées dans le code de l'application au lieu d'être déclarées en SQL: certains programmeurs craignent.

En tant que tel, si on a tendance à utiliser $_REQUEST partout, je peux faire tout ce que je peux avec GET via POST, ce qui signifie que vous devez configurer des balises <img> sur mon site (malveillant) qui poussent les utilisateurs connectés dans votre module de commerce électronique à acheter des produits en silence, ou je peux les amener à cliquer sur des liens qui entraîneront des actions dangereuses ou la révélation d'informations sensibles (probablement pour moi).

Cependant, cela est dû au fait qu'un programmeur novice, ou du moins inexpérimenté, PHP fait de simples erreurs. Tout d'abord, savoir quand les données de quel type sont appropriées. Par exemple, j'ai un service Web qui peut renvoyer des réponses en URLEncoding, XML ou JSON. L’application décide comment formater la réponse en vérifiant l’en-tête HTTP_ACCEPT, mais elle peut être forcée dans un autre en envoyant le paramètre format.

Lors de la vérification du contenu du paramètre de format, il pourrait être envoyé via une chaîne de requête ou une postdata, en fonction de nombreux facteurs, le moindre étant de savoir si les applications appelantes souhaitent ou non que "& format = json" soit associé à sa requête. Dans ce cas, $_REQUEST est très pratique car cela me évite de taper quelque chose comme ceci:

$format = isset($_POST['format']) ? $_POST['format'] 
    : (isset($_GET['format']) ? $_GET['format'] : null);

Je ne vais pas m'étendre beaucoup plus loin, mais il suffit de dire que l'utilisation de $_REQUEST n'est pas dissuadée, car elle est intrinsèquement dangereuse - c'est juste un autre outil qui fait exactement ce qu'on lui demande, que vous compreniez ou non ces implications - c'est la décision pauvre, paresseuse ou mal informée d'un programmeur pauvre, paresseux ou inexpérimenté qui est à l'origine de ce problème.

Comment utiliser $_REQUEST en toute sécurité


  1. Connaissez vos données: Vous devriez vous attendre à savoir quel type de données vous obtiendrez, alors assainissez-les en conséquence. Des données pour une base de données? addslashes() ou *_escape_string(). Allez-vous le montrer à l'utilisateur? htmlentities() ou htmlspecialchars(). Vous attendez des données numériques? is_numeric() ou ctype_digit(). En fait, filter_input() et ses fonctions connexes ne sont conçus que pour vérifier et nettoyer les données. Utilisez ces outils, toujours.
  2. Ne pas accéder directement aux données de superglobales fournies par l'utilisateur}. Prenez l'habitude de nettoyer vos données à chaque fois et déplacez-les vers des variables propres, même s'il ne s'agit que de $post_clean. Alternativement, vous pouvez simplement nettoyer directement dans les superglobales, mais la raison pour laquelle je préconise l’utilisation d’une variable distincte est qu’il est ainsi facile de repérer les vulnérabilités dans le code, car n'importe quoi pointe directement vers un superglobal et non son désinfecté. équivalent est considéré comme une erreur dangereuse.
  3. _ {Sachez d'où devraient provenir vos données. En reprenant mon exemple, il est parfaitement raisonnable d'autoriser l'envoi de la variable de format de réponse via GET ou POST. J'autorise également l'envoi de la variable "action" via l'une ou l'autre méthode. Cependant, les actions elles-mêmes ont des exigences très spécifiques quant à savoir quel verbe HTTP est acceptable. Les fonctions, par exemple, qui modifient les données utilisées par le service ne peuvent être envoyées que par POST. Les demandes relatives à certains types de données sans privilège ou à privilèges faibles (telles que des images de carte générées dynamiquement) peuvent être servies en réponse aux demandes émanant de l'une ou l'autre méthode.

En conclusion, rappelez-vous cette règle simple:

SÉCURITÉ IS CE QUE VOUS FAITES, PERSONNES!

MODIFIER:

Je fortement recommande le conseil de bobince: si vous le pouvez, définissez le paramètre request_order dans php.ini sur "GP"; c'est-à-dire pas de composant cookie. Il n’ya pratiquement aucun raisonnement rationnel à cela dans plus de 98% des cas, car les données de cookie ne devraient presque jamais être considérées comme comparables à la chaîne de requête ou aux données postérieures.

P.S., Anecdote!

Je connaissais un programmeur qui pensait à $_REQUEST un endroit où stocker simplement des données accessibles de manière superglobale. Les noms d'utilisateur et mots de passe importants, les chemins d'accès aux fichiers, vous le nommez et il était stocké dans $_REQUEST. Il était un peu surpris (bien que ce ne soit malheureusement pas comique, malheureusement) lorsque je lui ai expliqué comment se comportait cette variable. Inutile de dire que cette pratique a été abandonnée.

8
Dereleased

C'est vague. Vous ( ne savez pas vraiment comment les données vous ont été transmises car elles contiennent des données de publication, d'obtention et de cookie. Je ne pense pas nécessairement que ce soit toujours une mauvaise chose, à moins que vous ayez besoin de connaître ou de restreindre le mode de livraison.

7
Sampson

J'aime vraiment l'utiliser. Il vous donne la possibilité d’utiliser GET ou POST, ce qui peut s'avérer utile pour des formulaires tels que les formulaires de recherche dans lesquels la plupart du temps, les données sont postées, mais parfois, vous aurez envie de mentionner un lien vers une recherche particulière. vous pouvez utiliser les paramètres GET à la place.

En outre, si vous examinez de nombreux autres langages (ASP.NET par exemple), ils ne font aucune distinction entre les variables GET et POST.

ETA

Je n'ai jamais utilisé REQUEST pour obtenir les valeurs COOKIE, mais je pense que Kyle Butt fait une bonne remarque dans les commentaires sur ce post à ce sujet. Ce n'est PAS une bonne idée d'utiliser REQUEST pour obtenir les valeurs COOKIE. Je pense qu'il a raison de dire que, si vous agissez de la sorte, il existe un réel potentiel de falsification de requêtes inter-sites.

De plus, l'ordre dans lequel les éléments sont chargés dans REQUEST est contrôlé par les paramètres de configuration dans php.ini (variables_order et request_order). Donc, si vous avez la même variable transmise via à la fois POST et GET, celle que vous insérez dans REQUEST dépend de ces paramètres ini. Cela pourrait affecter la portabilité si vous dépendez d'un ordre particulier et si ces paramètres sont configurés différemment de ce que vous attendez.

3
Eric Petroelje

La seule utilisation de $_REQUEST n’est pas une mauvaise idée, c’est avec GET.

  • Si vous l'utilisez pour charger des valeurs POST, vous risquez des contrefaçons de requêtes intersites.
  • Si vous l'utilisez pour charger des valeurs de cookies, vous risquez à nouveau des contrefaçons de requêtes intersites

Et même avec GET, $_GET est plus court à taper que $_REQUEST;)

2
Jani Hartikainen

Il est important de comprendre quand utiliser POST, quand utiliser GET et quand utiliser un cookie. Avec $ _REQUEST, la valeur que vous regardez pourrait provenir de l’un d’eux. Si vous vous attendez à obtenir la valeur d'un POST, d'un GET ou d'un COOKIE, il est plus instructif pour quelqu'un qui lit votre code d'utiliser la variable spécifique au lieu de $ _REQUEST.

Une autre personne a également fait remarquer que vous ne souhaitez pas que tous les POST ou cookies soient remplacés par des requêtes GET car il existe différentes règles intersites pour chacune d'elles, par exemple, si vous renvoyez des données ajax en utilisant $ _REQUEST, vous êtes vulnérable. à une attaque de script intersite.

2
Kyle Butt

Darren Cook: "Depuis PHP 5.3, le php.ini par défaut indique que seules les données GET et POST sont placées dans $_REQUEST. Voir php.net/request_order I just Est tombé sur ce dossier -pause de compatibilité lors de l’attente d’un cookie que les données se trouvent dans $_REQUEST et se demandent pourquoi cela ne fonctionne pas! "

Wow ... certains de mes scripts ont cessé de fonctionner à cause d'une upgrade vers PHP 5.3. Fait la même chose: supposons que les cookies soient configurés lors de l’utilisation de la variable $_REQUEST . Avec la mise à niveau, cela ne fonctionnait plus.

J'appelle maintenant les valeurs de cookie séparément à l'aide de $_COOKIE["Cookie_name"]...

0
Arjan202

Je pense qu’il n’ya pas de problème avec $_REQUEST, mais il faut être prudent lors de son utilisation car c’est un ensemble de variables provenant de 3 sources (GPC).

Je suppose que $_REQUEST est toujours disponible pour rendre les anciens programmes compatibles avec les nouvelles versions php, mais si nous démarrons de nouveaux projets (y compris de nouvelles bibliothèques), je pense que nous ne devrions plus utiliser $_REQUEST pour rendre les programmes plus clairs. Nous devrions même envisager de supprimer les utilisations de $_REQUEST et de les remplacer par une fonction de wrapper pour alléger le programme, en particulier lors du traitement de grandes données de texte soumises, puisque $_REQUEST contient des copies de $_POST.

// delete $_REQUEST when program execute, the program would be lighter 
// when large text submitted
unset($_REQUEST);

// wrapper function to get request var
function GetRequest($key, $default = null, $source = '') 
{
  if ($source == 'get') {
    if (isset($_GET[$key])) { 
      return $_GET[$key]; 
    } else { 
      return $default; 
    }
  } else if ($source == 'post') {
    if (isset($_POST[$key])) { 
      return $_POST[$key]; 
    } else { 
      return $default; 
    }
  } else if ($source == 'cookie') {
    if (isset($_COOKIE[$key])) { 
      return $_COOKIE[$key]; 
    } else { 
      return $default; 
    }
  } else {
    // no source specified, then find in GPC
    if (isset($_GET[$key])) {
      return $_GET[$key];     
    } else if (isset($_POST[$key])) {
      return $_POST[$key]; 
    } else if (isset($_COOKIE[$key])) {
      return $_COOKIE[$key]; 
    } else {
      return $default; 
    } 
  }
}
0
user953985

Je ne serai peut-être utilisé que si vous souhaitez récupérer l'URL ou le nom d'hôte en cours, mais pour analyser des données à partir de cette URL, telles que des paramètres, à l'aide du symbole &, ce n'est probablement pas une bonne idée. En général, vous ne voulez pas utiliser une description vague de ce que vous essayez de faire. Si vous avez besoin d'être spécifique, c'est là que $ _REQUEST est mauvais, si vous n'avez pas besoin d'être spécifique, n'hésitez pas à l'utiliser. Je penserais.

0
Brian T Hannan

Si vous connaissez les données que vous souhaitez, vous devez les demander explicitement. IMO, GET et POST sont deux animaux différents et je ne vois pas pourquoi il serait nécessaire de mélanger les données de publication et les chaînes de requête. Si quelqu'un en a un, je serais intéressé.

Il peut être pratique d’utiliser $ _REQUEST lorsque vos scripts peuvent répondre à GET ou à POST de la même manière. Je dirais cependant que cela devrait être un cas extrêmement rare et que, dans la plupart des cas, deux fonctions distinctes permettant de gérer deux concepts distincts, ou tout au moins la vérification de la méthode et la sélection des variables correctes, sont préférées. Le flux de programme est généralement beaucoup plus facile à suivre lorsqu'il n'est pas nécessaire de faire une référence croisée à l'origine des variables. Soyez gentil avec la personne qui doit maintenir votre code dans 6 mois. Ça pourrait etre vous.

En plus des problèmes de sécurité et des WTF causés par les cookies et les variables d'environnement dans la variable REQUEST (ne me lancez pas sur GLOBAL), réfléchissez à ce qui pourrait se passer dans le futur si PHP commençait à supporter nativement d'autres méthodes telles que PUT. et DELETE. Bien qu'il soit extrêmement improbable que ces éléments soient fusionnés dans le superglobal REQUEST, il est possible qu'ils soient inclus en tant qu'option dans le paramètre variable_order. Vous n'avez donc aucune idée de ce que REQUEST contient et de ce qui prévaut, en particulier si votre code est déployé sur un serveur tiers.

Est-ce que POST est plus sûr que GET? Pas vraiment. Il est préférable d'utiliser GET lorsque cela est pratique car il est plus facile de voir dans vos journaux comment votre application est exploitée lorsqu'elle est attaquée. POST est préférable pour les opérations qui affectent l'état du domaine car les spiders ne les suivent généralement pas et les mécanismes de récupération prédictifs ne suppriment pas tout votre contenu lorsque vous vous connectez à votre CMS. Cependant, la question ne portait pas sur les avantages de GET vs POST, mais sur la manière dont le destinataire devrait traiter les données entrantes et pourquoi il est mauvais de les fusionner. Il ne s'agit donc que d'un BTW.

0
Duncan