Modification directe des superglobaux

20

J'ai vu des gens (qui écrivent généralement du bon code) modifier directement le $_POSTtableau avec un code comme celui-ci:

// Add some value that wasn't actually posted
$_POST['last_activity'] = time();

// Alter an existing post value
$_POST['name'] = trim($_POST['name']);

// Our pretend function
// Pass the entire $_POST array as data to work with in the function
// The function update_record() will read only the values we actually need
update_record($_POST);

// ...That sure was easier than creating a new array 
//  with only the $_POST values we actually need.

Il est logique de update_record()ne pas accéder directement à $ _POST, nous pouvons donc lui passer d'autres tableaux de données, par exemple, mais c'est sûrement paresseux, de mauvaise conception ou peut-être tout simplement faux? Cependant, nous transmettons toujours un tableau valide à update_record(), alors pourquoi en créer un nouveau?

Ce n'est pas le but de la question, juste un exemple d'utilisation. Cependant, j'ai entendu beaucoup de gens dire que cela ne devrait pas être fait avec des $_REQUESTdonnées, et c'est une mauvaise pratique. Mais pourquoi? Semble assez inoffensif.

Exemples:

  • Définition d'une valeur par défaut $_GET(ou post) qui n'existe pas vraiment

  • Ajout de $_POSTvaleurs qui n'ont pas été réellement publiées après la soumission d'un formulaire

  • Assainissement ou filtrage $_GETdirect des valeurs ou des clés du tableau très tôt dans le script (assainissement de secours ... pourquoi pas?)

  • Définir une $_POSTvaleur manuellement avant la soumission du formulaire pour remplir une entrée avec une valeur par défaut (lorsque l'entrée lit $_POSTpour sa valeur par défaut; je l'ai fait)

  • Créer vos propres $_SERVERvaleurs? Bien sûr, pourquoi pas?

  • $_COOKIEEt les autres, comme et $_SESSION? Bien sûr, nous devons les modifier directement non? Alors pourquoi pas les autres?

La modification directe des superglobaux ne devrait-elle jamais doit-elle être effectuée, ou est-ce OK dans certains cas?

Wesley Murch
la source
Je serais d'accord avec # 1, # 2 et # 3 car c'est une utilisation inattendue (en particulier # 1 et # 2).
Kevin Peno
Bonne question. La modification des tableaux globaux est incorrecte de la même manière que l'utilisation de valeurs globales est incorrecte. De plus, ces tableaux ont leur but (passer des paramètres de l'extérieur) qui fait de leur modification un moyen direct de gâcher le code. Mais, je crois que certains de ces tableaux peuvent être nettoyés au début du script, juste pour ne pas causer de problèmes dans le code.
Tadeck
1
J'utilise des wrappers de tableaux d'entrée OO (filtrage implicite), qui affichent une notification supplémentaire lorsque les variables $ _GET ou $ _POST sont altérées. C'est toujours possible, mais devrait être limité à des situations étroites. (Signalisation inter-modules, bien que seul le répartiteur / contrôleur frontal devrait en avoir besoin.)
mario
@mario: J'adorerais en savoir plus sur la façon dont vous avez accompli cela si vous pouvez jeter un œil à cette question: stackoverflow.com/questions/12954656
Wesley Murch

Réponses:

16

Étant donné que PHP définit déjà ces superglobaux, je ne pense pas que ce soit mauvais de les modifier. Dans certains cas, cela peut être le meilleur moyen de résoudre les problèmes ... en particulier lorsqu'il s'agit de code tiers que vous ne pouvez pas facilement modifier. (Ils peuvent utiliser $_GETdirectement ou supposer qu'une clé existe dans $_SERVER, etc.)

Cependant, d'une manière générale, je pense que c'est une mauvaise pratique lorsque vous écrivez votre propre code. Modifier les $_REQUESTdonnées avec un filtre en arrière-plan qui s'exécute automatiquement sur chaque page est susceptible d'introduire des effets secondaires. (Voir tous les problèmes que les "guillemets magiques" ont causés pour preuve.)

Donc, si vous n'allez pas le faire (filtrer automatiquement les superglobaux), ce qui suit ne vous offre aucun avantage:

$_POST['foo'] = filter($_POST['foo']);

quand vous pouvez facilement faire:

$foo = filter($_POST['foo']);

Je pense qu'il est beaucoup plus clair de faire la distinction à l'échelle du site $_POSTet qu'il $_GETs'agit toujours de données non filtrées et non fiables, et elles ne devraient jamais être utilisées telles quelles .

En copiant la valeur filtrée dans une autre variable, vous prétendez que "je comprends ce que je fais ... j'ai filtré cette entrée et elle est sûre à utiliser".

Konforce
la source
Merci pour votre contribution, mon Internet est hors service depuis près de 2 jours, je n'ai donc pas eu la possibilité de répondre à qui que ce soit. Dans l'exemple, j'ai modifié $ _POST et l'ai utilisé comme un tableau de données à passer à une fonction de mise à jour, en supposant qu'il existe plusieurs autres clés $ _POST que nous lirons dans cette fonction. Je préférerais créer un nouveau tableau mais j'ai vu des gens le faire à la place, donc je ne suis toujours pas sûr de l'appeler ou non "mauvais code", mais je pense que c'est au moins de cette façon. Je pense que chaque fois que vous ressentez le besoin de le faire, il y a toujours une meilleure façon.
Wesley Murch
1
@Wesley, la principale raison pour laquelle il est "mauvais" est qu'il est beaucoup plus probable que vous oubliez de nettoyer certaines données utilisateur. Dans votre exemple, vous modifiez une clé puis passez le tableau entier. Que faire si certaines de ces données contiennent des entrées malveillantes qui ne sont pas traitées? Il est préférable de créer ce nouveau tableau à la main, en copiant uniquement les éléments dont vous avez besoin $_POST, en les désinfectant au fur et à mesure. Et en ce qui concerne d'autres personnes qui font cela ... eh bien, beaucoup de gens écrivent un très mauvais code PHP, mais ce n'est pas une excuse pour vous aussi. :)
konforce
Je pense que j'aurais dû insister sur les autres applications de l'abus des superglobales en plus de la simple désinfection des données. J'aurais probablement dû laisser tout à fait de côté et écrire une question plus claire, les gens aiment particulièrement revenir sur les aspects de sécurité et ignorent souvent le reste. Pour ne pas sembler ingrat, j'apprécie vraiment les commentaires. Je vais attendre un jour et cochez celle-ci, car vous avez abordé quelques bons points mais vous avez manqué le vote pendant les 3 minutes lorsque la question était nouvelle :) Merci encore!
Wesley Murch
9

Je suggérerais généralement que vous ne devriez pas modifier les super-globaux prédéfinis afin qu'il soit clair ce qui est des données filtrées et quelles sont les données brutes / non fiables.

D'autres pourraient suggérer que si vous nettoyez les superglobales au début du cycle de demande, vous n'avez pas à vous en préoccuper ailleurs.

Je les associerais toujours quand vous en avez besoin avec:

$id = (int)$_POST['id'];

ou similaire.

En ce qui concerne les autres variables , il est bon de ne pas écrire à l' une des $_GET, $_POST, $_REQUEST, $_SERVERou $_COOKIE. $_SESSIONcependant, c'est différent parce que vous voulez souvent écrire des données dans la session qui sont ensuite persistées sur différentes requêtes de la session.


la source
2
Plus de raisons pour lesquelles ces types de globaux devraient disparaître remplacés par des objets / méthodes qui peuvent être appelés pour les obtenir lorsque cela est nécessaire. Pourquoi setcookieexiste- t- il, mais nous obtenons des cookies via $_COOKIE? De plus, comme il $_COOKIEn'est défini qu'au démarrage de la session en cours et n'est jamais mis à jour, il nécessite que vous modifiiez / définissiez les cookies dans les deux zones afin que les zones ultérieures du code aient des informations à jour.
Kevin Peno
Merci James, je suis déconnecté depuis un moment donc je n'ai pas pu répondre. Pour faire court, je suis d'accord avec vous. Il y a toujours une meilleure solution que d'écrire pour publier / obtenir / etc, mais je ne sais toujours pas si c'est considéré comme une mauvaise idée, comme dans " ne jamais faire ça jamais ". Donc, si je retrouve ce type de code, pensez-vous que j'ai le droit de "les appeler" sur du code bâclé, ou peut-il être utilisé de manière intelligente et sûre parfois?
Wesley Murch
@Wesley Si c'était "ne jamais faire ça", les superglobaux seraient probablement strictement en lecture seule - ils ne le sont pas. Je dirais simplement que c'est une mauvaise pratique de les définir ou de les remplacer dans votre code d'application - pour lesdites raisons.
Michel Feldheim
3

Vous devriez l'éviter. Peut-être qu'un certain temps vous avez oublié de nettoyer quelque chose, vous pouvez alors récupérer des données dangereuses. Si vous copiez les données dans une nouvelle structure pendant la désinfection

  • Vous obtenez seulement ce que vous voulez / avez besoin et pas ce qui se trouve $_POSTaussi
  • Vous obtiendrez probablement une erreur, si le tableau nouvellement créé manque certaines clés ou manque du tout

D'autres scripts supplémentaires peuvent supposer que le tableau est intact et peuvent réagir curieusement.

KingCrunch
la source
2

Je n'ai jamais aimé l'idée de modifier le superglobale car elle est trompeuse. C'est un moyen rapide et hacky de faire quelque chose qu'il y aura probablement une meilleure façon de faire.

Si vous modifiez la valeur de $_POST , par exemple, vous dites que le logiciel a reçu des données qu'il n'a pas reçues.

LE VRAI PROBLÈME

Il y a une situation réelle où cela devient un gros problème:

Imaginez que vous travaillez en équipe. Dans un monde idéal, tout le monde utilise la même syntaxe, mais nous ne vivons pas dans un monde idéal. Un développeur, John, aime accéder aux données publiées à l'aide de $_POST. Il change quelque chose dans les post-vars:

$_POST['ranking'] = 2; // John has changed ranking from 1 to 2 for whatever reason

Ensuite, vous avez un autre développeur, Chris, qui préfère utiliser filter_inputpour accéder aux données entrées (c'est-à-dire GET, POST, SERVER, COOKIE) car il va protéger le logiciel lors du traitement des données que l'utilisateur peut altérer. Dans sa partie du logiciel, il doit obtenir la valeur de poste de ranking. Sa partie du code est AFTER John's.

$ranking = filter_input(INPUT_POST, 'ranking', FILTER_SANITIZE_NUMBER_INT);
// $ranking = 1

Dans l'exemple ci-dessus, en changeant un superglobal, vous avez cassé PHP. John a défini la valeur de $_POST['ranking']2 pour une raison quelconque, mais maintenant Chris a reçu une valeur de 1

Quand je n'ai vu aucun autre moyen de le faire:

J'ai travaillé sur un projet qui utilisait wordpress comme blog derrière un équilibreur de charge AWS. Cela change la valeur de $_SERVER['remote_address']. Dans ce cas, l'autre développeur n'a eu d'autre choix que de procéder comme suit:

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $parts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    $_SERVER['REMOTE_ADDR'] = $parts[0];
}

Conclusion

Il y a presque certainement un meilleur moyen que de changer les superglobaux

Luke Madhanga
la source
1

Je pense que la vraie question ici est «pourquoi devriez-vous modifier le thème?». Je ne vois aucune raison valable de le faire. Si vous devez nettoyer un imput, vous pouvez utiliser une variable locale…

À moins que votre code soit suffisamment court (disons, moins de 50 lignes de long), la modification de ces super-globales ne ferait que rendre votre code plus difficile à maintenir et à comprendre.

Soit dit en passant, vous n'avez pas besoin de passer $ _POST à ​​la fonction, car il s'agit d'un tableau superglobal auquel on peut accéder même dans la portée locale d'une fonction.


la source
3
Mais il devrait le passer. Sinon, il est très difficile de tester et il n'est pas possible d'appeler la fonction / méthode avec d'autres valeurs sans aucun
piratage
Eh bien, cela dépend de ce que fait sa méthode. S'il est conçu uniquement pour analyser ce qui se trouve sur le tableau $ _POST, il n'a pas besoin de le transmettre. Bien sûr, si cela sert un objectif plus général / abstrait, vous avez raison.
2
@Thomas, je suis d'accord avec King ici. Même s'ils sont globaux, vous ne devez pas utiliser quoi que ce soit global dans d'autres étendues car cela provoque un couplage étroit (c'est pourquoi la fonction ne peut pas être réutilisée). Étant donné votre exemple, si la fonction est de nettoyer les données, pourquoi ne nettoie-t-elle que les $_POSTdonnées? La transmission $_POSTrend la fonction aseptiser toutes les données.
Kevin Peno,
0

Après avoir d'abord répondu à cette question en disant qu'il ne devrait pas y avoir de raison de modifier les superglobaux, je modifie cette réponse avec un exemple de moment où j'ai décidé de le faire.

Je travaille actuellement sur une table de base de données de réécriture d'URL dans laquelle la requestcolonne dirige l'utilisateur vers son correspondanttarget colonne .

Par exemple, un requestpourrait être blog/title-hereet targetpourrait l'être blog.php?id=1.

Depuis blog.phpattend des $_GETvariables, et je ne veux pas changer le header("Location:"), je suis laissé faire quelque chose comme ceci:

$uri    = explode('?', $uri_request)[0];
$params = explode('?', $uri_request)[1];
parse_str($params, $_GET);

Cela crée un $_GETtableau contenant les paramètres voulus transmis par la targetcolonne.

En fin de compte, je déconseille fortement de modifier les superglobales à moins que vous ne deviez absolument le faire .

rybo111
la source