cross-site-scripting

Cross-Site-Scripting

Als Cross-Site-Scripting auch XSS genannt, bezeichnet man eine Angriffsart bei der Sicherheitslücken ausgenutzt werden, um bei dem Client schadhaften Code auszuführen. XSS Angriffe sind überall da möglich, wo Benutzereingaben ohne weitere Prüfung an einen Browser zur Weiterverarbeitung gesendet werden. Da sich XSS Angriffe, wie schon erwähnt, an die Benutzer einer Webanwendung richten, kommen Clientseitige Scriptsprachen wie Javascript zum Einsatz. Durch diese könne sensible Daten wie Benutzernamen und Passwörter, z.B bei Login Formularen, ausspioniert werden und ein Dritter kann sich somit unerlaubten Zugang zum Account verschaffen.

Wie vermeidet man nun XSS Angriffe?

Um solche Angriffe zu vermeiden, sollten alle Benutzereingaben geprüft, HTML-Tags und Sonderzeichen entfernt bzw. maskiert werden.

Um die Benutzereingaben auf gültige Zeichen zu prüfen bieten, sich so genannte Whitelist Prüfungen bzw. reguläre Ausdrücke an. Der Vor- und Zuname einer Person enthält in der Regel nur Groß- und Kleinbuchstaben und keine Zahlen oder Sonderzeichen. Eine E-Mail Adresse oder Internetadresse hat eine bestimmte Syntax. Postleitzahlen haben eine bestimmte Anzahl von Zahlen und bestehen nur aus Ziffern.

Mehr Informationen zu regulären Ausdrücken findet Ihr hier.....

Bei Benutzereingaben wie Kommentaren, Forenbeiträgen oder Gästebucheinträgen ist die Überprüfung der Eingaben nicht ganz so einfach. Hier muss man zwangsläufig Satzzeichen, Sonderzeichen, Buchstaben und Zahlen zulassen. Wenn man seinen Besuchern noch die Möglichkeit bieten möchten die Beiträge etc. individuell zu gestalten, so muss man HTML-Tags zulassen. Hier kann man auf die PHP-Funktionen strip_tags() und htmlentities() zurückgreifen.

Wie strip_tags() funktioniert und wie man es einsetzt, beschreibe ich in Angriffe durch das Manipulieren von Parametern.

Die Funktion htmlentities() wandelt alle HTML-Sonderzeichen in Entity-Codes um. So wird aus dem folgenden String:

<b><u>Ich bin ein XSS Angriff<⁄u><⁄b>
nach dem anwenden von htmlentities():
&lt;b&gt;&lt;u&gt;Ich bin ein XSS Angriff&lt;/u&gt;&lt;/b&gt;
Häufig werden HTML-Tags mit Attributen versehen, um Namen zu vergeben, auf CSS Klassen zuzugreifen oder um Formulardaten mit vordefinierten Werten zu kennzeichnen. Hierbei sollte man die Attribute immer in einfachen oder doppelten Anführungszeichen setzten, um bei Benutzereingaben diese mit htmlentities() in Entity-Codes umzuwandeln.

In dem Beispiel wird die Funktion htmlentities() um die Konstante ENT_QUOTES erweitert, denn so lassen sich auch einfache und doppelte Anführungszeichen in den entsprechenden Entity-Code umwandeln.

Beispiel:

<?php

$string = ′<script languag="javascript">alert('XSS');</script>′
$string_ent = htmlentities($string,ENT_QUOTES);

?>
aus:
<script languag="javascript">alert('XSS');</script>
wird nach dem Einsatz von htmlentities():
&lt;script languag=&quot;javascript&quot;&gt;alert(&#039;XSS&#039;);&lt;/script&gt;
Verwendet man htmlentities() in Kombination mit strip_tags(), so sind XSS Angriffe nicht mehr ohne weiteres möglich.

Möchte man seinen Usern trotzdem die Freiheit bieten Texte zu formatieren, wäre eine BBCode Klasse zu empfehlen.

Auch legitime Funktionen der Internet Browser können ausgenutzt werden um an sensible Daten von Besuchern ran zukommen.

Benutzername/Passwort Kombinationen können über den Browser im Password Safe hinterlegt werden. Wenn man nun den Password Safe benutzt, muss man sich beim nächsten Login nicht mehr die Login Daten merken, denn sie werden automatisch in die entsprechenden Formularfelder eingefügt. Dabei wird das Passwort sowohl im Passwort Safe, wie auch beim Einfügen in das Formularfeld in Klartext dargestellt, was eine nicht unerhebliche Gefahr darstellt. Auch wenn das Passwort als *** im Formularfeld dargestellt wird, kann man dies mittels DOM (Document Object Modell) auslesen.

Um automatische Formularvervollständigungen zu vermeiden, kann man dynamische Formularfelder verwenden.

Als erstes generiert man mit Hilfe der PHP Funktionen md5() und rand() einen zufälligen Schlüssel.

Beispiel:

<?php

$schluessel = md5(rand(0,99999));

?>
Um nun die Formularvervollständigung zu verhindern, erstellt man statt einer herkömmlichen String-Variable ein Array, das den vorher erstellten Schlüssel dann als Array-Schlüssel verwendet. Um Werte in einen Formular mit Hilfe eines Array zu übergeben, fügt man bei dem Name des Formularfeldes eckige Klammern hinzu.

Beispiel:

<form>
     <input type="text" name="benutzername[<?php echo $schluessel ?>]">
     <input type="password" name="passwort[<?php echo $schluessel ?>]">
     <input type="hidden" name="schluessel" value="<?php echo $schlussel ?>">
     <input type="submit">
</form>
Im Formular wird ein Hidden Feld, also ein verstecktes Formularfeld erstellt, das den Schlüssel für das Array übergibt um auf die Werte aus dem Formular zugreifen zu können.

Möchten man nun für die Weiterverarbeitung auf die Benutzerdaten zugreifen, funktioniert das nach dem Absenden des Formulars wie folgt:

Beispiel:

<?php
     $schluessel = $_POST['schluessel'];
     $benutzername = $_POST['benutzername'][$Schluessel];
     $passwort = $_POST['passwort'][$schluessel];
?>
Mit diesem einfachen Trick, lässt sich die automatische Formularvervollständigung austricksen.

Header Variablen enthalten Informationen über den Server und dessen Ausführungsumgebung. Auch wenn Benutzer keinen direkten Zugriff auf die Variablen haben, so können diese mit Browser Plugins manipuliert werden. Sprich, auch aus dieser Variable können Parameter mit bösen Absichten übergeben werden, aus diesen Grund sollte man auch Header Variablen stets wie Benutzereingaben behandeln.

Bei der Entgegennahme von Formularfeldern, sollte man auf die Super Globale Variable $_REQUEST verzichten, da diese alle Werte aus den Request Methoden $_POST und $_GET beinhaltet. So kann also nie sichergestellt werden, wo genau die Werte herkommen die mit $_REQUEST abgerufen werden.

So wäre es z. B. Möglich, ein Script, dessen Formulardaten mit $_REQUEST entgegengenommen wurden, über die URL Parameter zu übergeben und auszuführen. Was wiederum vom Entwickler eventuell nicht so gewollt ist.

Wird ein Formular abgeschickt, empfiehlt es sich zu überprüfen ob dies auch vom Anwender so gewollt ist, damit der Angreifer keine Aktionen im Namen der Benutzer ausführen kann, ohne das die Benutzer etwas davon mitbekommen.

Beispiel:

<?php

session_start();

     function check_form_token($form_token){
          if(!isset($_SESSION[$form_token.'_token')){
              return false;
     }

     if(isset($_POST['token'])){
          return false;
     }

     if($_SESSION[$form.'_token'] !== $_POST['token']){
          return false;
     }
          return true;
}

     function token($form){

          $token = md5(uniqid(microtime(),true));
          $_SESSION[$form.'_token'] = $token;
          return $token;
     }
Wenn nun auf der Webseite ein Formular verwendet werden soll, generiert man zuerst mit der selbst geschrieben Funktion token() einen Token und fügt dieses dann mit einem hidden Feld ins Formular ein. Des weiteren weist man dem Wert, beim Aufruf der Funktion, eine Session Variable zu.

Beispiel:

<?php

     $token = token('form');

?>

<from>
<input type="hidden" name="token" value="<?php echo $token ?>">
</form>
Nach dem Absenden des Formulars, überprüfen wir nun mit der Funktion check_form_token(), ob eine Session Variable mit dem Index in unserem Beispiel "form_token" vorhanden ist. Wenn dies der Fall ist, wird überprüft, ob das Token aus der Session Variable mit dem Token des Formulars $_POST['token'] übereinstimmt. Sollten diese Bedingungen zutreffen wird, das Formular ganz normal verarbeitet. Falls nicht, sollte man die Verarbeitung abbrechen.

Beispiel:

<?php

     if(check_form_token('form')){
          //Formular verarbeiten
     }else{
          //Verarbeitung abbrechen
     }
?>
Auf diese Weise kann man Seitenübergreifende Manipulationsversuche verhindern.