PHP_SELF ist böse! Potentielles Cross Site Scripting (XSS)!
Geschrieben von skaldrom am 7. Mai 2008
Was haben wir gelernt?
Ja, uns wurde gelehrt, dass man wenn immer möglich nicht Dateinamen direkt, sondern eine Variable angeben soll, die für den Dateinamen steht. Warum konnte mir zwar noch niemand so genau sagen, aber ich nehme an, dass es darum geht, dass der Dateinamen oder der Pfad ändern könnte. So habe ich ziemlich oft ganz brav geschrieben:
...
</form>
Und (zum Glück) bin ich nicht der Einzige. Eine kleine Suche auf Googles Codesearch hat gezeigt, dass mindestens Mambo, PHPMyFAQ, Einige WordPressthemes und viele mehr dasselbe Problem haben. Ich bin bei Weitem auch nicht der Erste, der über Probleme mit dieser Technik erfahren und darüber geschrieben hat.
Problem? mit $_SERVER['PHP_SELF']?
Lasst mich ausholen: Der Apache Webserver hat eine Option AcceptPathInfo, welche standardmässig auf On ist. Mit dieser Option mappt der Apache beliebig lange Pfade auf Dateien, sofern diese irgendwie Bestandteil des Pfades sind. Der Rest wird in Umgebungsvariablen mitgegeben.
Gimme Code
Nehmen wir an, es gäbe eine Datei /subdir/mypath.php welche so aussieht:
echo "<pre>";
echo "REQUEST_URI: ".$_SERVER['REQUEST_URI']."\n";
echo "PHP_SELF: ".$_SERVER['PHP_SELF']."\n";
echo "SCRIPT_NAME: ".$_SERVER['SCRIPT_NAME']."\n";
echo "</pre>";
?>
Bei einem Aufruf von: http://localhost/subdir/mypath.php/additional/stuff/nonsense.php?para=4 mappt Apache netterweise alles auf unsere Datei http://localhost/subdir/mypath.php und verstaut den Rest im $_SERVER Array. Die Ausgabe ist:
REQUEST_URI: /subdir/mypath.php/additional/stuff/nonsense.php?para=4 PHP_SELF: /subdir/mypath.php/additional/stuff/nonsense.php SCRIPT_NAME: /subdir/mypath.php
PHP_SELF übernimmt also den ganzen Krempel und würde ihn bei unserem Form auch so darstellen. Angenommen, wir haben ein PHP-Script mit der URL http://localhost/contact/myform.php mit folgendem Inhalt:
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method ="post">
Ruft man dieses nun mit folgender URL auf (die aufwändiger als notwendig konstruiert und des besseren Verständnisses wegen nicht URL-encodiert ist):
http://localhost/contact/myform.php/"></form>Hier ein Javascript: <script>alert('gotcha');</script><form action="/contact/myform.php
erhält man:
<form action="/"></form>Hier ein Javascript: <script>alert('gotcha');</script><form action="/contact/myform.php" method ="post">
Also vollkommen gültiges HTML (sogar das Form funktioniert) mit fremdbestimmbaren Seiteninhalt. Das ist ja wohl hässlich…
Theorie! Gib mir Praxis!
Ich weiss nicht, wie lange folgende Links funktionieren, beziehungsweise diese Sites anfällig für diese Art von XSS sind:
Digital Postcard (Kein XSS, aber mein Text
):
![]()
Multimediatreff: (Mittlerweile behoben)
![]()
Jobs. ch (Mittlerweile behoben):
![]()
Was nutzt das dem bösen Hacker?
Text in Fremdpages einbauen, Phishing, Indentitätenklau und noch einiges Weiteres. Ein Folgeartikel wird mindestens eine Anwendung zeigen.
Was tun?
Ganz einfach: Das oft verschmähte $_SERVER['SCRIPT_NAME'] verwenden!!!
BTW: Viele Variablen in $_SERVER sind anfällig, aber alles muss ich ja auch nicht verplappern, oder?
30. August 2008 um 4:09
Naja eigentlich sollte man Server Vars auch nur im Hintergrund verwenden.
Zb mit denen eine var machen die wiederum als basis für die eigentlich zweckmäßige var ist.
auch könnte man diese vars dann vor der interpretation durch iene function jagen die nur gewünschten inhalt zulässt oder zumindest einige prüfungen macht
so könnte man den ganzen mist bereits im vorherein abfangen
30. August 2008 um 9:38
@Bofh
Jup, auf jeden Fall sollte man den Variablen von Aussen kein Bisschen trauen. Es gibt viele verschiedene Filtermöglichkeiten und man muss aufpassen, dass man keine Fehler macht und dann trotzdem wieder XSS-Lücken provoziert…
14. April 2010 um 22:45
Danke Chummer,
Da hat gerade der Platz 1 auf der SERP ganz gut zum akuten Code gepasst…
Man freut sich, zur rechten Zeit das rechte bisschen Info zu bekommen und verbastelt es gerne alternativ zur Angriffsfläche.
Die Menschheit wird verrückt…
22. April 2010 um 21:19
gut zu wissen
5. Mai 2010 um 1:45
@skaldrom
Hallo, ich habe deine Angaben gerade getestet, und habe dafür
<form action="” method=”post”>
geschrieben, aber wenn ich:
http://localhost/web/kontakt.php/”>Hier wurde Javascript eingeschmuggelt!alert(‘Du bist erledigt!’);<form action="/web/kontakt.php
in meiner adressleiste eingebe, dann sehe ich keie Änderung oder Verbesserung, ich erhalte dann trotzdem den Text auf der seite und auch eine js-alertbox
Was soll jetzt an $_SERVER['SCRIPT_NAME'] besser sein?
Ich hab das nicht ganz verstanden, sorry. Daniel
Upps ich sehe gerade das der code entschärft wir…als ich habe php_self durch script_name ersetzt…und sehe keine änderung, das js-script wird trotzdem verarbeitet:-(
5. Mai 2010 um 8:45
Ich habe Dir gemailt wegen dem PHP-Code und werde den hier ergänzen. Grundsätzlich hängt SCRIPT_NAME all das zusätzliche gewurstel nicht an…
17. Juni 2010 um 22:51
So ein Quatsch. Der Request-Pfad kommt halt von außen, und alles was von außen kommt muss in einem Kontext, in dem bestimmte Zeichen eine Funktion haben, escaped werden. In diesem Fall ist der Kontext ein HTML-Quellcode und darin haben bekanntermaßen <, >, & und " eine Funktion.
Wie wär’s mal mit
???
Das ist absolut grundlegendes Handwerkszeug.
18. Juni 2010 um 9:10
Hm?
- Was ist besser: Infos von Aussen, escaped: PHP_SELF
- Infos, die gar nicht vom bösen Internet berührt werden: SCRIPT_NAME
Deine Lösung geht so auch, ich empfinde sie aber als suboptimal ohne Zusatznutzen.
Ausserdem: Der Ton macht die Musik.
23. Oktober 2010 um 0:13
Und wo genau steckt hier die Unsicherheit? Ja, du als “böser Hacker” kannst dir selbst einen Javascript-Code ausgeben, oder dir selbst deine Cookies auslesen, oder für dich selbst die Anzeige der Seite manipulieren. Aber wie willst du andere User dazu bringen diesen “Exploit” zu verwenden, bzw damit an Daten anderer User kommen? Ich sehe dazu keine Möglichkeit ehrlichgesagt.
24. Oktober 2010 um 21:31
Nun, hier einige Möglichkeiten:
Wenn die Leute dann draufklicken kann ich ihre Cookies auslesen… Oder habe ich Dein Anliegen falsch verstanden?
18. August 2011 um 14:38
Alles was nach einem “Daten-Trenner” aussieht (sprich ” ‘ <– diese verwende ich), wird bei mir als erstes in den entsprechenden ASCII-Code umgewandelt.
$var=eregi_replace("'",''',$var);
$var=eregi_replace('"','"',$var);
$var=strip_tags($var);
return $var;
}
if(isset($_POST)){foreach($_POST as $pk => $pw){$_POST[$pk]=CLEAR_USER_VARS($_POST[$pk]);}
if(isset($_GET)){foreach($_GET as $gk => $gw){$_GET[$gk]=CLEAR_USER_VARS($_GET[$gk]);}
18. August 2011 um 15:23
Aber das putzt PHP_SELF nicht, oder?
19. August 2011 um 6:59
Doch, genau das tut es und jede andere Schwachstelle auch SQL-Injection z.B. . Wenn man Trennzeichen vorher entfernt, können keine Anweisungen unterbrochen werden. Außerdem braucht man bei Formularen das Action-Attribut nicht reich aus.
19. August 2011 um 9:48
Ist nur ein Detail, aber Du putzt $_SERVER nitte, damit auch nicht PHP_SELF. Wenn Du das aber tust und die Codierung so tragbar ist für die App, dann bist Du mit Deinem Code sicher gut unterwegs.