PHP: So schützen Sie sich vor Cross Site Scripting (XSS) – Teil 1
von dieter | Kategorie: Allgemein, knowhow
Innerhalb einer Webanwendung oder Webseite entstehen immer dann Sicherheitslücken, wenn von dem Benutzer Eingaben gefordert sind. Diese werden in eine Datenbank gespeichert oder auf dem Bildschirm ausgegeben. Der Benutzer hat also direkten Einfluss auf die Ausgabe/Speicherung und kann diese für seine Zwecke manipulieren und missbrauchen, sofern seine Eingaben nicht zuvor durch geeignete Maßnahmen gefiltert werden.
Das Problem muss an zwei Stellen angegangen werden: zum einen müssen Eingaben eines Benutzers vor der Ausgabe auf dem Bildschirm auf gefährliche Inhalte geprüft werden. Zum anderen müssen Eingaben, die in die Datenbank gespeichert werden, ebenfalls auf darin enthaltenen Code untersucht werden, da der Angreifer im schlimmsten Fall Datensätze auslesen, manipulieren oder löschen kann. Der 1. Teil beschäftigt sich mit den Ausgaben auf dem Bildschirm.
Möglichkeiten des Benutzers, das System zu beeinflussen
Cross Site Scripting (XSS), das auf die direkte Ausgabe von Benutzereingaben abzielt, wird als nicht-persistent / reflexiv bezeichnet. Das liegt daran, dass der Schadcode nur temporär vorhanden, aber nicht gespeichert wird. Wenn auf einer Webseite z.B. die Suche genutzt wird, könnte die url so aussehen:
http://mywebsite.com/?search=words
Und der Suchbegriff (“words” im obigen Beispiel) könnte auf Ihrer Webseite wie folgt ausgegeben werden:
Ihre suche nach words ergab folgende Treffen
der Angreifer könnte diese Anzeige ausnutzen, und folgenden Suchbegriff verwenden:
<script type="text/javascript">alert("XSS")</script>
Als Folge würde der Browser diese Zeile nicht als einfachen Begriff, sondern als ausführbaren Code interpretieren und einen Javascript-Alert mit “XSS” erzeugen. Dieser Angriff ist in dieser Form zwar harmlos, jedoch sollte bedacht werden, dass der Angreifer jeglichen ausführbaren Javascript-Code in das Suchfeld einfügen kann.
Persistente bzw. beständige Angriffe entstehen dadurch, dass Benutzereingaben über bspw. ein Formular getätig, serverseitig gespeichert und immer wieder an bestimmten Stellen ausgegeben werden. Der Angriff folgt dabei dem selben Schema wie bei nicht-Persistenten, nur dass der Angreifer den schädlichen Code in Formularfelder einfügt. Bei dieser Art von Cross Site Scripting (XSS) besteht des Weiteren die Gefahr, dass andere Besucher der Seite von diesem mit betroffen sind, da der schädliche Code gespeichert wurde und je nach Seitenstruktur für jeden dargestellt wird.
Maßnahmen gegen Cross Site Scripting(XSS)
PHP bietet einige Maßnahmen, die gegen Cross Site Scripting (XSS) schützen sollen.
- stripslashes(): Die Funktion entfernt alle Backslashes aus einem Begriff. so würde bspw. aus dem Begriff “H\a\l\l\0 Welt” lediglich “Hallo Welt”. In Programmiersprachen wie bspw. PHP oder Scriptsprachen wie Javascript wird der Backslash verwendet, um das nachfolgende Zeichen als String und nicht als Programmelement zu werten. Dadurch könnte ein Angreifer an der Stelle, an der die Eingabe ausgegeben wird, eigenen Code einschleusen, in dem er von Ihnen verwendete Programmelemente “auskommentiert” und durch seine Eigenen erweitert.
- strip_tags(): Diese Funktion verbietet die Verwendung von Tag-Elementen, wie sie für Javascript,Flash und HTML bentötigt werden. <b> oder <script> würde von PHP selbst durch ein Leerzeichen ersetzt werden. Dies ist zum Einen schon eine gute Maßnahme, kann aber auch zuviel des Guten bedeuten, sofern der Benutzer Eingaben über bspw. einen RTE (Rich Text Editor) tätigt und seine Ausgabe in bspw. einem Gästebuch formatieren möchte. Alternativ kann bei strip_tags() ein zweiter Parameter mit erlaubten Zeichenketten mitgegeben werden, was aber den Schutz wiederrum mindert.
- htmlspecialchars(): Diese Funktion ist effektiv gegen Cross Site Scripting (XSS). Sie wandelt viele spezielle Zeichen in den dafür vorgesehenen HTML-Code um. <, <, & sowie einfache und doppelte Anführungszeichen werden in HTML-Zeichenketten umgewandelt, die vom Browser richtig dargestellt werden, aber keinen Einfluss auf den PHP-Code haben, was sie ohne Umwandlung in jedem Fall hätten, wie schon im ersten Beispiel erläutert.
- htmlentities(): Bietet diesselbe Funktionalität wie htmlspecialchars(). Jedoch werden bei dieser Funktion wirklich alle Zeichen in HTML-Zeichenketten umgewandelt. Eine vollständige Liste aller Umwandlungen findet sich unter ascii.cl
Nun kennen Sie schon die wichtigsten Maßnahmen, um gegen Cross Site Scripting (XSS) vorzugehen. Allerdings existieren Möglichkeiten, diese Schutzmechanismen zu umgehen. Ein Beispiel stellt folgende Zeichenkette dar:
javascript:eval(String.fromCharCode(97,108,101,114,116,40,39,88,83,83,39,41))
Dieses Codebeispiel erzeugt diesselbe Aussgabe wie schon das erste Beispiel. der Angreifer hat es also trotz sämtlicher Schutzmaßnahmen geschafft, Code in Ihr System einzuschleusen. PHP bietet gegen diese Art von Angriffen keinen wirksamen Schutz. Daher besteht die einzige Möglichkeit darin, eine eigene Funktion gegen diese Angriffe zu verwenden.
function SEQ_OUTPUT($string_ = '') {
$string = mb_convert_encoding($string_, "UTF-8", "7bit, UTF-7, UTF-8, UTF-16, ISO-8859-1, ASCII");
$output = '';
for ($i = 0; $i < mb_strlen($string); $i++) {
if (preg_match('/([a-zA-Z0-9_.-])/', $string[$i])) {
$output .= $string[$i];
continue;
}
$byte = ord($string[$i]);
if ($byte <= 127) {
$length = 1;
$output .= sprintf("%04s;", dechex(uniord__(mb_substr($string, $i, $length))));
} else if ($byte >= 194 && $byte < = 223) {
$length = 2;
$output .= sprintf("%04s;", dechex(uniord__(mb_substr($string, $i, $length))));
} else if ($byte >= 224 && $byte < = 239) {
$length = 3;
$output .= sprintf("%04s;", dechex(uniord__(mb_substr($string, $i, $length))));
} else if ($byte >= 240 && $byte < = 244) {
$length = 4;
$output .= sprintf("%04s;", dechex(uniord__(mb_substr($string, $i, $length))));
}
}
return $output;
}
function uniord__($c) {
$h = ord($c{0});
if ($h <= 0x7F) {
return $h;
} else if ($h < 0xC2) {
return false;
} else if ($h <= 0xDF) {
return ($h & 0x1F) << 6 | (ord($c{1}) & 0x3F);
} else if ($h <= 0xEF) {
return ($h & 0x0F) << 12 | (ord($c{1}) & 0x3F) << 6
| (ord($c{2}) & 0x3F);
} else if ($h <= 0xF4) {
return ($h & 0x0F) << 18 | (ord($c{1}) & 0x3F) << 12
| (ord($c{2}) & 0x3F) << 6
| (ord($c{3}) & 0x3F);
} else {
return false;
}
}
Diese Funktionen wandeln sämtliche Sonderzeichen (Also z.B. auch runde Klammern) in Hexadezimal-Notation um. Der Browser versteht diese Art von Umwandlungen und zeigt sie wie gewohnt an, jedoch ist Code, der in dieser Form umgewandelt wurde, völlig unbrauchbar und ihre Seite somit vor Cross Site Scripting (XSS) geschützt. Ein Angreifer hat keine Chance, diese Umwandlung zu umgehen. Möchten sie also für Ihre Seite den bestmöglichen Schutz, können sie auf sämtliche PHP-Funktionen verzichten, wenn sie stattdessen diese beiden Funktionen vor jeder Benutzerausgabe verwenden.
Der große Nachteil dieser Funktionen liegt in der Speicherung in eine Datenbank. Benutzereingaben werden, falls Sie diese Funktion für die Speicherung von Daten verwenden, auch als Hexadezimal-Zeichenketten in die Datenbank gespeichert und werden dadurch unleserlich. Alternativen für die sichere Speicherung in Datenbanken werden im 2. Teil der Reihe "So schützen Sie sich vor Cross Site Scripting (XSS)" behandelt.


24 Mai 2013, 14:14 Uhr
Hallo,
sehr interessant – aber den 2. Teil zu lesen wäre auch noch schön!