devian: Gefahren beim Kontextwechsel: Variablen in der URL die der User

Guten Tag,
ich habe den Artikel zum Kontextwechsel ( http://aktuell.de.selfhtml.org/artikel/php/kontextwechsel/ ) gelesen, bin aber aus dem Teil, wo es um URLs geht nicht schlau geworden.

Folgendes passiert auf meiner Homepage häufig:
In einem Formular wird eine Eingabe des Users durch die URL an ein PHP Script gesendet. Dort angekommen wird sie schließlich auf der Seite ausgelesen. MEine Frage ist nun, mit welchen Maßnahmen schütze ich mich dagegen, dass ein User irgendeinen Script über das Formular ausführt? Angenommen er sendet irgendwie sowas: <script>[... hier wird meine Seite gehackt] </script>.

Zur sicherung habe ich die variable, gleich nachdem sie im PHP_Script empfangen wird mit htmlspecialchars() versehen. Also so:

$variable=htmlspecialchars($_GET['variable'], ENT_QUOTES);

später wird sie dann so im Browser mir $variable ausgebeben.
Im Anderen Fall übergebe ich sie wieder an eine URL:

header("LOCATION: testscript.php?variable=$variable");

Ist mein Vorgehen so sicher?

  1. Hi devian.

    In einem Formular wird eine Eingabe des Users durch die URL an ein PHP Script gesendet. Dort angekommen wird sie schließlich auf der Seite ausgelesen.

    Du liest die Eingabe aus? Was bedeutet das?

    MEine Frage ist nun, mit welchen Maßnahmen schütze ich mich dagegen, dass ein User irgendeinen Script über das Formular ausführt?

    Der User kann selber nichts "ueber das Formular ausfuehren", er kann nur Daten senden. Nur DU (sprich: das verarbeitende Skript), kannst bewirken, dass eventuell gesendeter Code ausgefuehrt wird.

    Angenommen er sendet irgendwie sowas: <script>[... hier wird meine Seite gehackt] </script>.

    Dann steht dieser String in einem Feld des Arrays $_GET. Kein Problem. Problematisch wird es hoechstens dann, wenn der String in die HTML-Ausgabe des Skriptes eingebettet wird. Dann wuerde der Browser ihn ggf. ausfuehren.

    Zur sicherung habe ich die variable, gleich nachdem sie im PHP_Script empfangen wird mit htmlspecialchars() versehen. Also so:

    $variable=htmlspecialchars($_GET['variable'], ENT_QUOTES);

    später wird sie dann so im Browser mir $variable ausgebeben.

    Das ist im Grunde das Richtige. Es ist aber nicht zu empfehlen, extra die Variable $variable einzufuehren. Gib einfach htmlspecialchars($_GET['variable']) direkt aus.

    Im Anderen Fall übergebe ich sie wieder an eine URL:

    header("LOCATION: testscript.php?variable=$variable");

    Dabei kommt i.a. Unsinn raus. Selbst, wenn Du hier wirklich das HTML-Literal (sprich: die htmlspecialchars()-Rueckgabe) der urspruenglichen Eingabe uebergeben willst (was hoechstwahrscheinlich unsinnig ist) - das tust Du hier nicht. Wenn Du den Wert der Variablen $variable an ein anderes Skript weiterleiten willst, dann musst Du in den URL sein URL-Literal (sprich: den Rueckgabewert von url_encode($variable)) schreiben.

    Viele Gruesse,
    der Bademeister

  2. Hi!

    In einem Formular wird eine Eingabe des Users durch die URL an ein PHP Script gesendet. Dort angekommen wird sie schließlich auf der Seite ausgelesen. MEine Frage ist nun, mit welchen Maßnahmen schütze ich mich dagegen, dass ein User irgendeinen Script über das Formular ausführt? Angenommen er sendet irgendwie sowas: <script>[... hier wird meine Seite gehackt] </script>.

    Wo findet das Ausführen statt? Im Browser. Also muss der Browser die Daten so erhalten, dass er sie nicht als Anweisung interpretiert. Das lässt sich dadurch erreichen, dass die <http://de.selfhtml.org/html/allgemein/zeichen.htm#html_eigene@title=HTML-eigenen Zeichen> maskiert werden. Wenn also ein &lt; statt eines < in den an den Browser ausgelieferten Daten steht, wird er das nachfolgende script nicht als Anweisung ansehen sondern es es lediglich als Buchstaben auf dem Bildschirm anzeigen. Das sieht zwar doof, wenn man das auf der Seite sieht, ist aber harmlos. Du bist mit der HTML-gerechten Behandlung der Daten nicht gegen unsinnigen Inhalt geschützt, aber gegen dessen Ausführen.

    Zur sicherung habe ich die variable, gleich nachdem sie im PHP_Script empfangen wird mit htmlspecialchars() versehen. Also so:
    $variable=htmlspecialchars($_GET['variable'], ENT_QUOTES);

    Das ist der falsche Zeitpunkt. Die HTML-kodierung nützt dir nur etwas im HTML-Kontext. Der ist aber nicht jetzt sondern erst irgendwann später, wenn überhaupt.

    später wird sie dann so im Browser mir $variable ausgebeben.

    Erst zu diesem Zeitpunkt solltest du die HTML-Behandlung vornehmen.

    Im Anderen Fall übergebe ich sie wieder an eine URL:
    header("LOCATION: testscript.php?variable=$variable");

    Hier hast du keinen HTML-Kontext sondern eine URL vorliegen. Für URLs haben andere Zeichen eine Sonderbedeutung, weswegen du hier eine URL-Kodierung benötigst.

    Wenn in $variable ein & enthalten ist - und das wird passieren, weil es beispielsweise bei &lt; vorkommt, so wird das beim Lesen des Querystrings als Ende des Wertes angesehen. Dein Wert wird also vorzeitig abgeschnitten und der folgende Rest stiftet auch noch Verwirrung. Die URL-kodierung sorgt jedoch dafür, dass unter anderem das & URL-gerecht notiert wird und somit die Eindeutigkeit zwischen & als Inhaltsbestandteil und & als gewolltem Trennzeichen gesichert ist.

    Wenn du jedoch nun einfach dahergehst und noch die URL-Kodierung zu deiner htmlspecialchars-Behandlung hinzufügst, so bist zu war auf der sicheren Seite, jedoch bekommt der Empfänger, der die URL liest, nun einen HTML-kodierten Wert. Das ist normalerweise ungünstig, weil er nun einen bereits kodierten Wert vorliegen hat, aber andererseits aus anderen Quellen unkodierte Daten bekommt und nun aufpassen muss, wann noch welche Behandlung vorzunehmen ist. Abgesehen davon, kann es sein, dass die Daten nun gar nicht in den bereits vorbereiteten Kontext ausgegeben werden, sondern in einen anderen, was dann zunächst eine Dekodierung aus dem alten Zusatand und eine anschließende Kodierung für das neue Medium erfordert. Liest sich verworren? Nunja, das ist der Code am Ende auch, wenn man zu früh behandelt. Deshalb ist es besser, nur mit Rohdaten zu arbeiten und erst beim Übergang in einen anderen Kontext die dafür notwendige Behandlung vorzunehmen.

    Hinzu kommen nun noch die fachlichen Anforderungen, also dass Werte je nach Anforderung der Anwendung auf bestimmte Inhalte kontrolliert werden oder verarbeitet werden müssen. Auch hierfür ist es günstiger, mit Rohdaten arbeiten zu können.

    Ist mein Vorgehen so sicher?

    Du musst dich immer fragen: Welche Zeichen haben in einer bestimmten Situation eine besondere Bedeutung? Und wie notiert man sie, damit sie diese Bedeutung nicht haben, wenn das nicht gewünscht ist?

    Oder auch anders betrachtet: Die Syntaxregeln eines bestimmten Systems schreiben vor, wie Werte notiert werden müssen. Halte dich an diese Regeln, um keinen Syntaxfehler oder eine Fehlinterpretation zu bekommen.

    Besonderes Augenmerk muss dabei auf "verdeckte Werte" gelegt werden. Ein String in einem Programmcode ist offensichtlich. Wenn eine Maskierung vergessen wurde, wird der Syntaxfehler recht schnell auffallen. Ein Variableninhalt ist verdeckt, da sieht man nur den Variablennamen. Und wenn man nicht zufällig (oder besser gezielt) mit den Sonderzeichen als Eingabe testet, kommt das Versäumnis nicht gleich zum Vorschein.

    Lo!

  3. Hallo

    ich habe den Artikel zum Kontextwechsel ( http://aktuell.de.selfhtml.org/artikel/php/kontextwechsel/ ) gelesen, bin aber aus dem Teil, wo es um URLs geht nicht schlau geworden.

    Folgendes passiert auf meiner Homepage häufig:
    In einem Formular wird eine Eingabe des Users durch die URL an ein PHP Script gesendet. Dort angekommen wird sie schließlich auf der Seite ausgelesen. MEine Frage ist nun, mit welchen Maßnahmen schütze ich mich dagegen, dass ein User irgendeinen Script über das Formular ausführt? Angenommen er sendet irgendwie sowas: <script>[... hier wird meine Seite gehackt] </script>.

    Wird die Eingabe in eine MySQL-Datenbank geschrieben, muss der String für den Query mit mysql_real_escape_string (oder der mysqli-Variante) maskiert werden.

    Wird er in einer Textdatei gespeichert, lasse ihn, wie er ist.

    Zur sicherung habe ich die variable, gleich nachdem sie im PHP_Script empfangen wird mit htmlspecialchars() versehen. Also so:

    $variable=htmlspecialchars($_GET['variable'], ENT_QUOTES);

    Viel zu früh.

    später wird sie dann so im Browser mir $variable ausgebeben.

    Das wäre auch der richtige Zeitpunkt, htmlspecialchars anzuwenden. Beachte, dass es sein kann, dass du die Daten in einem anderen Kontext als HTML brauchst. *Dann* sind die HTML-gerecht maskierten zeichen fehl am Platz.

    Im Anderen Fall übergebe ich sie wieder an eine URL:

    header("LOCATION: testscript.php?variable=$variable");

    Abgesehen von der Tatsache, dass Location eine absolute URL erwartet (auch wenn viele Browser mit deinem Fehler leben können), liegt hier der Kontextwechsel vor. Der Inhalt des Parameters "variable" muss natürlich URL-Parametergerecht maskiert werden. Bei PHP erledigt das rawurlencode.

    Tschö, Auge

    --
    Verschiedene Glocken läuteten in der Stadt, und jede von ihnen vertrat eine ganz persönliche Meinung darüber, wann es Mitternacht war.
    Terry Pratchett, "Wachen! Wachen!"
    Veranstaltungsdatenbank Vdb 0.3