Cross-Site Scripting (XSS) unterbinden

Beim Cross-Site Scripting (XSS) wird die Karte „vertrauenswürdige Website“ ausgespielt. Wenn allerdings auf den Seiten der vom Benutzer vertrauten Website Scripte untergebracht sind, die nicht vertrauenswürdig sind, fällt das im ersten Augenblick nicht auf. Diese Scripte sind meistens JavaScripte, die durch andere Benutzer (in dem Fall Übeltäter) eingeschleust wurden. Wir haben also für Cross-Site Scripting mehrere Rahmenbedingungen:

  • Es können Skripte eingeschleust werden (PHP-Programm überprüft nicht Benutzereingaben)
  • Es werden Inhalte ungefiltert wieder angezeigt (PHP-Programm überprüft nicht Ausgaben)

Dies tritt meistens in Kombination auf, denn der Programmierer, der sich keine Gedanken über Sicherheit macht, beachtet beide Punkte nicht :).

Die Scripte können im simplen Fall „nur“ alle folgenden Besucher mit irgendwelcher Willkommensnachricht begrüßen, die aufpoppt und explizit geschlossen werden muss.

JavaScript
<script type="text/javascript">alert("XSS");</script>

oder kürzer:

JavaScript
<script>alert(?XSS?);</script>

XSS-Angriffe für sich genommen sind lästig – sie bilden allerdings die Grundlage für weitere Angriffe, die oft dazu genutzt werden, an sensible Daten zu kommen.

Im härtesten Fall können die Skripte unbemerkt die Identität des Nutzers stehlen und der Angreifer kann als „authentifizierter Nutzer“ sich dann auf dem Webangebot bewegen und unter Umständen (wenn angeboten) kostenpflichtige Dienste nutzen, die nachher dem entrüsteten Nutzer in Rechnung gestellt werden.

JavaScript
<javascript>gibt_mir_dein_cookie_und_tschuess()</javascript>

Anmerkung: Wer gehofft hat, hier Hacken zu lernen, liegt FALSCH! Daher der fiktive Aufruf der Funktion gibt_mir_dein_cookie_und_tschuess(), der effektiv auf einen anderen Server verweist. Traurigerweise gibt es viele Seite, die sich damit beschäftigen, wie man Möchtegernhacker wird, ohne die ursprüngliche Philosophie dahinter zu vermitteln.

Wenn man sich fragt, wo der Fall auftritt, dass ein Nutzer Eingaben machen kann, die von anderen Nutzern gelesen werden können, dann einfach mal an Gästebücher, Besucherforen usw. denken.

Das drastische ist, dass durch so eine Schwachstelle der gesamte Inhalt der Domain gefährdet wird. Im Hauruck-Verfahren wird zum bestehenden Angebot (z.B. eine Singlebörse) noch ein Diskussionsforum eingebaut. Weil man hier weder Zeit noch Geld aufwenden möchte, nimmt man eine Lösung Outofthebox, die leider diese Schwachstellen beinhaltet, und hat somit die eigentliche Anwendung gefährdet.

Eine Zeile im PHP-Programm in der Form:

PHP-Quellcode:
<?php
echo $_GET['benutzereingabe'];
?>

sollte tunlichst vermieden werden, wenn hier eine bereits bei der Erfassung ungefilterte Eingabe wieder ungefiltert ausgegeben wird.

Es sollte also bei der Ausgabe auf jeden Fall (wenn man weiß, dass keine HTML-TAGs auch ausgeben werden die Ausgabe über den PHP-Befehl „htmlentities“ entschärft werden.

PHP-Quellcode:
htmlspecialchars()

Alle kritischen Zeichen werden maskiert. Aus dem <jav.. (was notwendig ist, damit das JavaScript läuft) wird ein &gr; und es wird nachher auf der Ausgabe wirklich zu sehen sein: <jav.. – aber es wird keine JavaScript ausgeführt!

Von der unsicheren zu verbesserten Anwendung

Anhand des stark vereinfachten Beispiels eines Gästebuchs wird Schritt für Schritt auf die Probleme eingegangen und die unsicheren Bereiche erklärt und beseitigt. Der erstellte Quellcode ist auch kein valider HTML-Code, sondern soll so einfach wie möglich gehalten werden (dient zu Forschung und Lehre)

Funktion des Gästebuchs im Beispiel

In unserem Gästebuch kann nur ein Kommentar eingegeben werden, eine Textzeile reicht uns aus. Ein Feld für Name, E-Mail, Website schenken wir uns. Es würde das Beispiel nur unnötig aufblähen, aber nicht zum Erkenntnisgewinn beitragen. Es wird auch der Inhalt in eine Textdatei geschrieben. Das Beispiel können Sie zuhause ausprobieren, die ersten Stufen sollten Sie aber keinesfalls online stellen!

PHP-Quellcode
<form name="" action="" method="GET">
<input type="text" name="inhalt">
<input type="Submit" value="speichern">
</form>
 
<?php
$handle = fopen ( "gaestebuch.txt", "a" );
fwrite ( $handle, $_GET['inhalt'] . "<hr>\n" );
fclose ( $handle );
 
echo "<h2>Einträge Gästebuch";
readfile ("gaestebuch.txt");
?>

Je nach Einstellungen des Webservers werden JavaScript-Anweisungen bereits maskiert. Dann ist im Quellcode der Datei „gaestebuch.txt“ folgender Eintrag zu finden:

<h2>Einträge Gästebuch</h2>
Hallo Welt<hr />
<script type=\"text/javascript\">alert(\"XSS\");</script><hr>

Das bedeutet, dass in php.ini die magic_quotes gesetzt sind:

; Magic quotes for incoming GET/POST/Cookie data.
magic_quotes_gpc = On
<h2>Einträge Gästebuch</h2>
Hallo Welt<hr>
<script type=\"text/javascript\">alert(\"XSS\");</script><hr>   (magic_quotes_gpc = On)
<script type="text/javascript">alert("XSS");</script><hr> (magic_quotes_gpc = Off)

Und bei der Einstellung off wird nun bei jedem Aufruf der Datei eine Alert-Box mit der Ausgabe XSS für jeden Besucher angezeigt, die erst bestätigt werden muss.

Gibt allerdings der Angreifer etwas ohne Anführungsstriche ein, kommt er an dieser Einstellung vorbei:

<script type=text/javascript>alert(123);</script>

Durch den PHP-Befehl htmlentities wandeln wir nun von außen kommende Inhalte alle Zeichen in entsprechende HTML-Codes um. Das bedeutet in unserem Beispiel, aus dem Kleinerzeichen < wird nach der Umwandlung ein: &lt;

Durch die Umwandlung ist nun keine Ausführung mehr möglich, wenn auch der Eintrag im Klartext das Gästebuch verschandelt.

Gästebuch nach versuchten Anschlag

PHP-Quellcode
<form name="" action="" method="GET">
<input type="text" name="inhalt" />
<input type="Submit" value="speichern" />
</form>
 
<?php
$inhalt = htmlentities ($_GET['inhalt']);
$handle = fopen ( "gaestebuch.txt", "a" );
fwrite ( $handle, $inhalt . "<hr>\n" );
fclose ( $handle );
 
echo "<h2>Einträge Gästebuch</h2>";
readfile ("gaestebuch.txt");
?>

Und wenn wir wissen, dass keinerlei PHP und HTML-TAGs zugelassen sind, können wir über die PHP-Funktion strip_tags alles HTML- und PHP-Befehle entfernen lassen.

PHP-Quellcode:
<form name="" action="" method="GET">
<input type="text" name="inhalt">
<input type="Submit" value="speichern">
</form>
 
<?php
$inhalt = strip_tags ($_GET['inhalt']);
$inhalt = htmlentities ($inhalt);
$handle = fopen ( "gaestebuch.txt", "a" );
fwrite ( $handle, $inhalt . "<hr>\n" );
fclose ( $handle );
 
echo "<h2>Einträge Gästebuch</h2>";
readfile ("gaestebuch.txt");
?>

Danach bleibt von der Nutzereingabe „<script type=text/javascript>alert(123);</script>“ nur noch „alert(123);“ übrig.

Gästebuch mit Eingabeprüfung

Und trotzdem werden Sie an diesem Gästebuch keinerlei Freude haben, weil es zur Zeit der Sport von Spammern ist, alle Formulare, die irgendwo zu finden sind, auszufüllen. Das geschieht automatisiert und daher wird man in kürzester Zeit sehr viel Werbemüll für Viagra und Schmuddelseiten vorfinden, was man i.d.R. nicht haben möchte.

XSS-Angriffe für sich genommen sind lästig ? sie bilden oft die Grundlage für weitere Angriffe, die dazu genutzt werden, an sensible Daten zu kommen. XSS-Angriffe sind also die Vorbereitung zum Session-Hijacking, was im übernächsten Kapitel behandelt wird.