XSS-Gefahr: Server-Variable in PHP manipulierbar ($_SERVER['PHP_SELF'])

Nicht selten benötigt ein PHP-Script den Pfad zur derzeit ausgeführten Datei aus der URL bzw. relativ zum DocumentRoot, um ihn in z.B. ein A-Element in HTML einzufügen. Hierfür steht eine ab PHP 4.10 vordefinierte Variable $_SERVER zur Verfügung, welche ein Array mit Informationen zur aktuellen PHP-Laufzeit beinhält. Doch einige Werte des Arrays sind vom Client manipulierbar und stellen damit die Gefahr eines Angriffs auf den Server dar.

Die Variable $_SERVER['PHP_SELF'] ist eine Möglichkeit, den Pfad zum aktuellen Script zu ermitteln, doch der schöne Schein trügt: Bei schlechter Konfiguration eines Apache-Servers kann PHP_SELF eine breite Fläche für XSS-Angriffe (Cross Site Scripting, zu Deutsch etwa Kreuzen der Scripte verschiedener Server) bieten.

Ein kurzes Experiment soll dies veranschaulichen:

<?php

echo $_SERVER['PHP_SELF']."<br />"; // URL-Teil nach Domain des Servers, ohne HTTP-GET-Werte
echo $_SERVER['SCRIPT_NAME']."<br />"; // Pfad zum Script ab Document-Root
echo $_SERVER['REQUEST_URI']."<br /><br />"; // Gesamter URL-Teil nach Domain des Servers

// Weitere Pfade:
echo $_SERVER['DOCUMENT_ROOT']."<br />"; // Pfad zum Document-Root-Verzeichnis
echo $_SERVER['SCRIPT_FILENAME']."<br />"; // Absoluter Pfad zum aktuellen Script

?>

Wird dieser PHP-Code in einer Datei “test.php” gespeichert und mit einem Webserver (z.B. http://localhost/test.php) aufgerufen, so zeigen die ersten drei Zeilen der Ausgabe keine Unterschiede:

/test.php
/test.php
/test.php

C:/.../htdocs
C:/.../htdocs/test.php

Hängt man nun zusätzlich eine HTTP-GET-Variable hinter die aufgerufene URL an (z.B. http://localhost/text.php?variable=wert), so sehen die Ergebnisse des Tests folgendermaßen aus:

/test.php
/test.php
/test.php?variable=wert

C:/.../htdocs
C:/.../htdocs/test.php

Wie man erkennt, sind die hinzugefügten Zeichen in der Variable $_SERVER['REQUEST_URI'] enthalten, in den anderen beiden Möglichkeiten jedoch nicht.

Bei einem weiteren Versuch wird hinter dem Dateinamen der URL ein Slash / plus einige andere Zeichen gehängt (z.B. http://localhost/test.php/manipulation/?variable=wert):

/test.php/manipulation/
/test.php
/test.php/manipulation/?variable=wert

C:/.../htdocs
C:/.../htdocs/test.php

Nun haben die Indize PHP_SELF und REQUEST_URI die Zeichen hinter dem Dateinamen übernommen, alleine SCRIPT_NAME nicht.

Warum ist diese Handlung der Variablen nun gefährlich?

Oft werden sie in HTML-Tags für Verlinkungen ausgegeben. Da die Ausgabe jedoch manipulierbar ist, könnte ein Hacker z.B. Javascript einbinden und XSS für etliche Bedürfnisse nutzen.

Beispiel-Datei:

<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
[...]
</form>

Wird mit einem Browser nun eine manipulierte URL aufgerufen (z.B. http://localhost/text.php/”> <script>alert(“Gehackt!”);</script></form><form action=”/ ), so wird die HTML-Ausgabe folgendermaßen aussehen:

<form action="/"> <script>alert("Gehackt!");</script></form> <form action="/" method="post">
[...]
</form>

Es könnte jeder X-beliebige Code eingeschleust werden.

Warum passiert das?

Durch eine Option AcceptPathInfo des Apache-Konfigurationsfiles, welche standardmäßig auf On gesetzt ist.

Wie lässt sich ein Angriff vermeiden?

Indem man anstatt der Indize PHP_SELF oder REQUEST_URI zu SCRIPT_NAME greift.

Dieser Artikel wurde vertaggt mit , , , , , , .
Kategorien: Grundwissen, PHP

Hat Ihnen dieser Artikel gefallen? - Dann abonnieren Sie vlblog um über neue Themen rund ums Web informiert zu werden.

7 Kommentare zu “XSS-Gefahr: Server-Variable in PHP manipulierbar ($_SERVER['PHP_SELF'])”

  1. Horst sagt:

    Ein sehr guter Artikel. Eine Frage habe ich aber dennoch.
    Was passiert wenn man im Action-Attribut den Dateinamen weg lässt;
    dieser wird doch dann autom. vom Browser hinzugefügt, ist das auch manipulierbar?

  2. Vitus Lehner sagt:

    Danke, für das Feedback.
    Nein, bei einem leeren action-Attribut kann keinerlei Code eingeschleust werden, da die Ausgabe des Formulars keinen Einfluss durch den Client erfährt.
    Jedoch steht es dem Browser offen, wie er das leere Attribut behandelt und das Formular versendet.
    Mit SCRIPT_NAME dürftest du keine Probleme bekommen. ;)
    Gruß

  3. Maik sagt:

    Hi,

    sehr guter Beitrag. Allerdings ist die Lösung für mich zu kurz gekommen. Kann leider mit dieser Lösung nihts anfangen.
    Kannst du es bitte etwas genauer beschreiben.

  4. vitus37 sagt:

    Die Lösung ist letzten Endes nicht etwa

    <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">

    zu verwenden, sondern

    <form action="<?php echo $_SERVER['SCRIPT_NAME']; ?>" method="post">,

    da sich in $_SERVER['SCRIPT_NAME'] keine Daten vom Benutzer bzw. Angreifer einschleusen lassen.

  5. Hey,
    per mod_rewrite werden Get Variablen zu Ordnern in der Form /controller/parameter1/paramtere2/…/parameterN
    Nun kann ich doch trotzdem die Parameter wie folgt sicher auslesen, oder etwa nicht?
    $param = explode(‘/’,htmlspecialchars($_SERVER['REQUEST_URI']));
    Hatte erst eine Variante mit key($_GET), aber mir wurde dann zur Server Variablen geraten.
    Beste Grüße

    • vitus37 sagt:

      Ja, ist möglich. So arbeite ich auch immer. htmlspecialchars() ist nicht unbedingt nötig. Normal werden Benutzereingaben erst bei der HTML-Ausgabe kodiert.

  6. swaechter sagt:

    Vielen danke, sehr verständlich und ausreichend Umfangreich.

Hinterlasse eine Antwort