Archive for the ‘Security’ tag
HashDoS Angriff legt (unter anderem) PHP lahm
Ich bin leider die letzten 2 Tage nur wenige Stunden dazu gekommen die Live-Streams vom 28. Chaos Communication Congress (28C3) zu schauen, aber bzgl. PHP ist heute Nachmittag ein interessanter Talk gehalten worden mit dem Thema Effective Denial of Service attacks against web application platforms dem ich hier einen kurzen Artikel widmen werde.
Es geht darum wie PHP (und die anderen anfälligen Sprachen auch) Hash-Tabellen erstellen und verwalten. Die hier interessante Hash-Tabelle ist das $_POST Array, das man von außen füllen kann, und das anfällig ist wenn man nur genügend “passende” Datensätze reinfüllt. Der Algorithmus der die Hash-Tabelle befüllt wird nämlich langsamer sobald Kollisionen der Keys auftreten. Schickt man also beispielsweise 300KB POST-Daten an ein PHP-Script ist eine schnelle CPU damit ca. 30 Sekunden unter Volllast. Bei 8MB (dem Standard-Maximum für POST-Daten in der php.ini) wären es immerhin schon 5 Stunden, die die CPU benötigt um die Hash-Table zu füllen. Man kann also mit einer relativ kleinen DSL-Leitung einigen Schaden anrichten. Mit einer Gigabit-Leitung kann man so 10.000 CPU-Kerne dauerhaft beschäftigen.
Die Reporting-Funktion der Content-Security-Policy (CSP)
CSP hatte ich vor fast 2 Jahren bereits vorgestellt, mittlerweile hat es eine gute Verbreitung gefunden, sodass wir uns nochmals die Details anschauen. CSP ist ein Header, den der Server an den Browser schickt, und darin festlegt, von wo Javascripte, Bilder, CSS, Media-Dateien und mehr geladen werden dürfen. Mit sinnvollen Einstellungen ist es möglich, Cross Site Scripting (XSS) sowie Clickjacking zu verhindern, eine dieser essenziell wichtigen Einstellungen ist das Verbot von Inline-Javascript. Falls also ein Angreifer Javascript beispielsweise in die Datenbank einfügen kann, und bei der Ausgabe nicht oder falsch escaped wird, wird das Inline-Javascript das der Angreifer platziert hat nicht ausgeführt, XSS ist effektiv unterbunden.
In der Apache Konfiguration kann das beispielsweise so aussehen:
<VirtualHost *:80>
DocumentRoot /path/to/wwwroot
ServerName domain.de
Header add X-Content-Security-Policy "allow 'self'; img-src images.domain.de; script-src static.domain.de;"
</VirtualHost>oder hier mittels PHP gesetzt:
<?php
header("X-Content-Security-Policy: allow 'self'; img-src images.domain.de; script-src static.domain.de;");Sollten nun Bilder oder Javascripte eingebunden sein die nicht von den angegebenen Domains kommen wird der Browser sie blockieren und nicht laden. Es gibt neben img-src und script-src auch noch frame-src, xhr-src und weitere.
Was ist “Cross Site Request Forgery” (CSRF)?
Der ein oder andere mag es schon mal gelesen haben, aber es fristet nach wie vor ein Nischen-Dasein: Cross-Site Request Forgery.
Dieses Sicherheitsproblem von Webseiten aller Art (es macht eigentlich nur Sinn wenn es einen Login auf der Seite gibt) ist recht verbreitet, und ich möchte es hier zusammenfassen und Beispiele zeigen, wie auch eure Seiten dafür anfällig sind. Und natürlich Tipps geben, was man dagegen tun kann.
Das Grundproblem ist schnell erklärt: Ein Browser nutzt Tabs oder auch neue Fenster, um mehrere Seiten parallel öffnen und anzeigen zu können. Nehmen wir an, in einem Tab ist die Seite www.xing.com geöffnet, und in einem anderen Tab die Seite www.phpgangsta.de . Browser sind nun so konstruiert, dass sich diese beiden Seiten im Prinzip nicht gegenseitig beeinflussen können, d.h. mittels Javascript kann ich von meiner Seite aus nicht auf den Inhalt der geöffneten Xing-Seite zugreifen (Same Origin Policy).
Nun logge ich mich auf Xing ein. Wenn ich nun einen weiteren Tab öffne und www.xing.com aufrufe, bin ich dort ebenfalls eingeloggt. Beide Tabs nutzen also die selben Cookies, und genau das machen wir uns zu Nutze.
Was passiert nun also, wenn ich auf meiner Seite (www.phpgangsta.de) ein Bild einbinde, das so aussieht:
<img src=”http://www.xing.com/app/message?op=sendmessage&recipient=MichaelKliewe&body=Viagra+For+Free”>
oder auch
<iframe width=”0″ height=”0″ src=”http://www.xing.com/app/message?op=sendmessage&recipient=MichaelKliewe&body=Viagra+For+Free”></iframe>
(Dies sind nur Beispiele, Xing ist natürlich gegen CSRF abgesichert)
Der Browser des Besuchers, der ja noch einen weiteren Tab mit dem eingeloggten Xing-Account geöffnet hat, ruft diese URL auf, und verschickt damit Nachrichten über Xing, ohne dass es der Besucher möchte!
Genauso kann es also mit jeglichen URLs passieren, die irgendwelche Aktionen auslösen, beispielsweise User löschen, das Profil ändern.
<img src=”http://www.deine-seite.de/admin/user_delete.php?id=1″>
<img src=”http://www.meine-seite.de/add_admin.php?name=hacker&pass=hack”>
Sollte derjenige also gerade auf der entsprechenden Seite sein (in einem anderen Tab) und die Rechte für die jeweilige Aktion haben, wird sie ausgeführt. Der Browser sendet bei dem Aufruf des Links das passende Cookie mit, womit die Rechte passen und die Aktion erfolgreich ist. Da sind extrem üble Sachen denkbar. Beispielsweise war GMail anfällig, sodass jeder euren GMail-Account “fernsteuern” konnte (Emails schreiben, Emails löschen, Kontakte löschen usw). Da viele Leute Gmail nutzen und dort permanent eingeloggt sind, ist das gar nicht so unwahrscheinlich.
Oder aber stellt euch eine solche Webseite vor:
<html> Bei BrowsergameX gibt es ein Update. Bitte log dich ein und schau nach! <a href="http://www.browsergameX.de" target="_blank">BrowsergameX</a> <script> var url = 'http://www.browsergameX.de/transferMoney?amount=1000&target=1234567'; setTimeout(30000, "window.open(url)"); </script> </html>
Der User loggt sich also in seinem Spiel ein. Nach 30 Sekunden geht dann ein weiteres Fenster auf, und schwupps sind 1000 Geld-Einheiten eures Browsergame-Spielgelds weg.
Bei diesen Beispielen wurden nur GET-Parameter verwendet. Aber auch POST Parameter sind anfällig, es reicht also nicht, alles von GET auf POST zu ändern.
Sobald es dann um sensible Daten oder echtes Geld geht, ist der Spass vorbei. Was können wir also dagegen tun?
Wir müssen also sicherstellen, dass ein Link-Klick oder Formulardaten NUR von unserer Seite kommen kann. Erste Idee: Wir prüfen den Referrer, der müßte ja unsere Domain enthalten. Doch leider sendet nicht jeder Browser einen Referrer, und er lässt sich fälschen (Alles was von Clients kommt lässt sich fälschen und manipulieren!). Cookies lassen sich auch nicht nutzen.
Die einzig effektive Methode, dich aktuell bekannt ist, ist JEDEN Link und JEDES Formular um ein “secret token” zu ergänzen, das nur wir kennen und dynamisch generieren. Außerdem darf es nur begrenzt haltbar und nicht erratbar sein. Dieses Token prüfen wir dann nach dem nächsten Request und wissen dann, ob es von uns generiert wurde.
Marc Jakubowski hat in seinem Blog sehr brauchbaren Quelltext veröffentlicht, den man mit ein paar Anpassungen (unten drunter stehen einige Verbesserungsvorschläge) gut nutzen kann.
Schon haben wir einen effektiven Schutz gegen CSRF. Alle geschützten Aktionen können nur noch ausgeführt werden, wenn vorher auf unserer Seite der entsprechende Token generiert wurde. Außerdem unterdrücken wir damit als Nebeneffekt das doppelte Absenden von Formularen.
Natürlich ist das kein 100%-iger Schutz. Durch einfaches Brute-Force oder beispielsweise mit Hilfe der Browser-History (CSS Browser History Vulnerability) kann man den Token erraten.
Bei der Recherche bin ich auch über eine interessante Präsentation von Stefan Esser zum Thema “Secure Programming with Zend Framework” gestossen, worin auch das Thema CSRF kurz abgesprochen wird.
Mein letzter Tip, um euch als User im Internet zu schützen: Nutzt Firefox und das Addon NoScript, denn es blockt zB Cross-Domain Formulare und bietet auch Schutz gegen XSS.
Mehr Material über das Thema:
http://www.cgisecurity.com/csrf-faq.html
http://shiflett.org/articles/cross-site-request-forgeries


