Superglobale direkt modifizieren

20

Ich habe gesehen, dass Leute (die im Allgemeinen guten Code schreiben) das $_POSTArray direkt mit folgendem Code ändern :

// 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.

Es ist sinnvoll, update_record()nicht direkt auf $ _POST zuzugreifen, damit wir beispielsweise andere Arrays von Daten übergeben können, aber dies ist sicherlich faul, schlecht gestaltet oder möglicherweise einfach falsch? Wir übergeben jedoch immer noch ein gültiges Array an update_record(). Warum also ein neues erstellen?

Dies ist nicht der Punkt der Frage, nur ein Anwendungsbeispiel. Ich habe jedoch viele Leute sagen hören, dass dies nicht mit $_REQUESTDaten geschehen sollte , und es ist eine schlechte Praxis. Aber wieso? Sieht harmlos aus.

Beispiele:

  • Festlegen eines Standardwerts $_GET(oder Post-Werts), der nicht wirklich vorhanden ist

  • Hinzufügen von $_POSTWerten, die nach dem Absenden des Formulars noch nicht veröffentlicht wurden

  • Direkte Bereinigung oder Filterung der $_GETArray-Werte oder Schlüssel sehr früh im Skript (Fallback-Bereinigung ... warum nicht?)

  • Manuelles Festlegen eines $_POSTWerts vor dem Absenden des Formulars, um eine Eingabe mit einem Standardwert zu füllen (wenn die Eingabe $_POSTden Standardwert angibt; ich habe dies getan)

  • Deine eigenen $_SERVERWerte erfinden? Klar, warum nicht?

  • Wie wäre es mit den anderen, wie $_COOKIEund $_SESSION? Natürlich müssen wir diese direkt ändern, oder? Warum dann nicht die anderen?

Sollten Superglobale niemals direkt modifiziert werden, oder ist dies in einigen Fällen in Ordnung ?

Wesley Murch
quelle
Ich würde # 1, # 2 und # 3 zustimmen, da es sich um eine unerwartete Verwendung handelt (insbesondere # 1 und # 2).
Kevin Peno
Gute Frage. Das Ändern globaler Arrays ist genauso falsch wie das Verwenden globaler Werte. Auch diese Arrays haben ihren Zweck (Übergabe von Parametern von außen), der es einfach macht, sie zu ändern, um sich im Code zurechtzufinden. Ich glaube jedoch, dass einige dieser Arrays zu Beginn des Skripts bereinigt werden können, um nur keine Probleme im Code zu verursachen.
Tadeck
1
Ich verwende OO-Eingabe-Array-Wrapper (implizite Filterung), die einen zusätzlichen Hinweis ausgeben, wenn $ _GET- oder $ _POST-Variablen manipuliert werden. Es ist immer noch möglich, sollte aber auf enge Situationen beschränkt sein. (Modulübergreifende Signalisierung, obwohl nur der Dispatcher /
Frontcontroller
@mario: Ich würde gerne mehr darüber erfahren, wie Sie das geschafft haben, wenn Sie sich diese Frage ansehen können
Wesley Murch

Antworten:

16

Angesichts der Tatsache, dass PHP diese Superglobalen bereits setzt, halte ich es nicht für böse , sie zu modifizieren. In einigen Fällen kann dies die beste Möglichkeit sein, um Probleme zu lösen. Dies gilt insbesondere für Code von Drittanbietern, den Sie nicht einfach ändern können. (Sie könnten $_GETdirekt verwenden oder davon ausgehen, dass ein Schlüssel in $_SERVERusw. existiert .)

Generell halte ich es jedoch für eine schlechte Praxis, wenn Sie Ihren eigenen Code schreiben. Wenn Sie die $_REQUESTDaten mit einem Blick hinter die Kulissen-Filter ändern , der auf jeder Seite automatisch ausgeführt wird, kann dies zu Nebenwirkungen führen. (Sehen Sie alle Probleme, die "magische Anführungszeichen" für den Beweis verursacht haben.)

Wenn Sie dies nicht tun (die Superglobalen automatisch filtern), bietet Ihnen Folgendes keine Vorteile:

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

wenn du es einfach kannst:

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

Ich denke , es ist sehr viel klarer die standortweite Unterscheidung zu machen , dass $_POSTund $_GETsind immer ungefiltert, nicht vertrauenswürdige Daten, und sie sollen nie als Service - Leistung verwendet werden.

Indem Sie den gefilterten Wert in eine andere Variable kopieren, stellen Sie die Behauptung auf, dass "ich verstehe, was ich tue ... ich habe diese Eingabe gefiltert und sie ist sicher zu verwenden."

konforce
quelle
Vielen Dank für die Eingabe, mein Internet ist seit fast 2 Tagen ausgefallen, sodass ich keine Chance hatte, jemandem zu antworten. In diesem Beispiel habe ich $ _POST geändert und als Array von Daten für die Übergabe an eine Aktualisierungsfunktion verwendet, vorausgesetzt, es gibt mehrere andere $ _POST-Schlüssel, die wir in dieser Funktion lesen werden. Ich würde es vorziehen, ein neues Array zu erstellen, aber ich habe gesehen, dass die Leute dies stattdessen tun, daher bin ich mir immer noch ein bisschen unsicher, ob ich es als "schlechten Code" bezeichnen soll oder nicht, aber ich denke, es ist zumindest so. Ich denke, wann immer Sie das Bedürfnis haben, gibt es immer einen besseren Weg.
Wesley Murch
1
@Wesley, der Hauptgrund dafür, dass es "schlecht" ist, ist, dass es viel wahrscheinlicher ist, dass Sie vergessen, einige Benutzerdaten zu bereinigen. In Ihrem Beispiel ändern Sie einen Schlüssel und übergeben dann das gesamte Array. Was passiert, wenn einige dieser Daten böswillige Eingaben enthalten, die nicht verarbeitet werden? Es ist viel besser, dieses neue Array von Hand zu erstellen, indem Sie nur die benötigten $_POSTElemente kopieren und im Laufe der Zeit desinfizieren. Und was andere Leute betrifft, die das tun ... nun, viele Leute schreiben sehr schlechten PHP-Code, aber das ist auch keine Entschuldigung für Sie. :)
konforce
Ich denke, ich hätte die anderen Anwendungen des Missbrauchs von Superglobalen betonen sollen, abgesehen davon, dass nur Daten bereinigt wurden. Ich hätte es wahrscheinlich ganz weglassen und eine klarere Frage schreiben sollen, die Leute greifen besonders gerne die Sicherheitsaspekte auf und ignorieren den Rest oft. Um nicht undankbar zu klingen, schätze ich das Feedback wirklich. Ich werde eines Tages warten und dieses Häkchen setzen, da Sie einige gute Punkte angesprochen haben, aber die Abstimmungsstunde in den 3 Minuten verpasst haben, als die Frage neu war :) Nochmals vielen Dank!
Wesley Murch
9

Ich würde generell vorschlagen, dass Sie die vordefinierten Super-Globals nicht ändern, damit klar ist, was bereinigte Daten sind und was nicht vertrauenswürdige Rohdaten sind.

Andere schlagen möglicherweise vor, dass Sie sich keine weiteren Sorgen machen müssen, wenn Sie die Superglobalen zu Beginn des Anforderungszyklus bereinigen.

Ich würde sie immer vergleichen, wenn Sie sie brauchen mit:

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

o.ä.

In Bezug auf den anderen Variablen , ist es gut , die Praxis nicht zu einem schreiben $_GET, $_POST, $_REQUEST, $_SERVERoder $_COOKIE. $_SESSIONDies ist jedoch anders, da Sie häufig Daten in die Sitzung schreiben möchten, die dann für verschiedene Anforderungen in der Sitzung beibehalten werden.


quelle
2
Weitere Gründe, warum diese Art von Globalen verschwinden sollten, wurden durch Objekte / Methoden ersetzt, die aufgerufen werden können, um sie bei Bedarf abzurufen. Warum gibt setcookiees, aber wir erhalten Cookies über $_COOKIE? Da dies $_COOKIEnur festgelegt wird, wenn die aktuelle Sitzung startet und niemals aktualisiert wird, müssen Cookies in beiden Bereichen geändert / festgelegt werden, damit spätere Bereiche des Codes aktuelle Informationen enthalten.
Kevin Peno
Vielen Dank James, ich war eine Weile offline und konnte nicht antworten. Um es kurz zu machen - ich stimme Ihnen zu. Es gibt immer eine bessere Lösung als zu schreiben, um etwas zu posten / zu bekommen / usw., aber ich bin mir immer noch nicht sicher, ob es eine absolut schlechte Idee ist, wie in " Mach das niemals ". Wenn ich also wieder auf diese Art von Code stoße, glaube ich, dass ich das Recht habe, sie bei schlampigem Code "aufzurufen", oder kann dies manchmal auf clevere und sichere Weise verwendet werden?
Wesley Murch
@Wesley Wenn es so wäre, würden die Superglobalen wahrscheinlich nur Lesezugriff haben - das sind sie nicht. Ich würde es einfach als schlechte Praxis bezeichnen, sie in Ihrem Anwendungscode festzulegen oder zu überschreiben - aus den genannten Gründen.
Michel Feldheim
3

Sie sollten es vermeiden. Vielleicht haben Sie einmal vergessen, etwas zu bereinigen, und können dann gefährliche Daten abrufen. Wenn Sie die Daten während der Bereinigung in eine neue Struktur kopieren

  • Sie bekommen, was Sie wollen / müssen und nicht das, was in ist $_POSTzu
  • Sie erhalten wahrscheinlich eine Fehlermeldung, wenn im neu erstellten Array einige Schlüssel fehlen oder überhaupt nicht vorhanden sind

Zusätzliche andere Skripte können davon ausgehen, dass das Array unberührt ist und neugierig reagieren kann.

KingCrunch
quelle
2

Mir hat die Idee, Superglobal zu ändern, nie gefallen, weil sie irreführend ist. Es ist eine schnelle Hacky-Methode, um etwas zu tun, die es wahrscheinlich besser geben wird.

Wenn Sie beispielsweise den Wert von ändern $_POST, haben Sie damit angegeben, dass die Software Daten empfangen hat, die sie nicht erhalten hat.

DAS WIRKLICHE PROBLEM

Es gibt eine reale Lebenssituation, in der dies zu einem großen Problem wird:

Stellen Sie sich vor, Sie arbeiten in einem Team. In einer idealen Welt verwenden alle die gleiche Syntax, aber wir leben nicht in einer idealen Welt. Ein Entwickler, John, greift gerne auf veröffentlichte Daten zu $_POST. Er ändert etwas in den Post-Vars:

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

Dann haben Sie einen anderen Entwickler, Chris, der es bevorzugt, filter_inputauf eingegebene Daten (dh GET, POST, SERVER, COOKIE) zuzugreifen, um die Software zu schützen, wenn Daten verarbeitet werden, die der Benutzer manipulieren kann. In seinem Teil der Software muss er den Post-Wert von erhalten ranking. Sein Teil des Codes ist NACH Johns.

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

Im obigen Beispiel haben Sie durch Ändern eines Superglobals PHP beschädigt. John hat den Wert $_POST['ranking']auf 2 gesetzt, aus welchem ​​Grund auch immer, aber jetzt hat Chris den Wert 1 erhalten

Wenn ich keinen anderen Weg gesehen habe:

Ich habe an einem Projekt gearbeitet, das WordPress als Blog hinter einem AWS-Load-Balancer verwendet hat. Dies ändert den Wert von $_SERVER['remote_address']. In diesem Fall hatte der andere Entwickler keine andere Wahl, als Folgendes zu tun:

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

Fazit

Es gibt mit ziemlicher Sicherheit einen besseren Weg, als Superglobale zu ändern

Luke Madhanga
quelle
1

Ich denke, die eigentliche Frage hier lautet: "Warum sollten Sie das Thema ändern?". Ich sehe keinen triftigen Grund dafür. Wenn Sie einen Eingang bereinigen müssen, können Sie eine lokale Variable verwenden ...

Wenn der Code nicht kurz genug ist (z. B. weniger als 50 Zeilen lang), wird die Pflege und das Verständnis des Codes durch das Ändern dieser Super-Global-Codes nur erschwert.

Übrigens müssen Sie $ _POST nicht an die Funktion übergeben, da es sich um ein superglobales Array handelt, auf das auch im lokalen Bereich einer Funktion zugegriffen werden kann.


quelle
3
Aber er sollte es bestehen. Ansonsten ist es sehr schwer zu testen und es ist nicht möglich, die Funktion / Methode mit anderen Werten aufzurufen, ohne irgendwelche (noch hässlicheren) Hacks
KingCrunch
Nun, es hängt davon ab, was seine Methode tut. Wenn es nur zum Parsen von allem, was sich auf dem Array $ _POST befindet, entwickelt wurde, muss es nicht übergeben werden. Natürlich, wenn es einem allgemeineren / abstrakteren Zweck dient, dann haben Sie recht.
2
@Thomas, ich stimme King hier zu. Auch wenn sie global sind, sollten Sie in anderen Bereichen nichts Globales verwenden, da dies zu einer engen Kopplung führt (weshalb die Funktion nicht wiederverwendet werden kann). Wenn es in Ihrem Beispiel darum geht, $_POSTDaten zu bereinigen, warum werden dann nur Daten bereinigt ? Durch $_POSTdie Weitergabe werden alle Daten bereinigt .
Kevin Peno
0

Nachdem ich diese Frage zum ersten Mal mit den Worten beantwortet habe, dass es keinen Grund geben sollte, Superglobale zu ändern, bearbeite ich diese Antwort mit einem Beispiel für eine Zeit, in der ich mich dazu entschlossen habe.

Momentan arbeite ich an einer URL-Rewrite-Datenbanktabelle, wobei die requestSpalte den Benutzer zu der entsprechenden targetSpalte weiterleitet.

Zum Beispiel requestkönnte ein sein blog/title-hereund sein targetkönnte blog.php?id=1.

Da Variablen blog.phperwartet $_GETwerden und ich die nicht ändern möchte header("Location:"), muss ich Folgendes tun:

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

Dadurch wird ein $_GETArray erstellt, das die beabsichtigten Parameter enthält, die von der targetSpalte übergeben werden.

Letztendlich würde ich dringend davon abraten, Superglobale zu modifizieren, es sei denn, Sie müssen dies unbedingt tun .

rybo111
quelle