Vorherige Teile der Serie
CSRF steht für Cross-Site Request Forgery und läuft komplett beim Opfer ab. Das einzige, was der Angreifer tut, ist dem Opfer einen speziellen Link zuzuschicken. GMail war mal anfällig für CSRF-Attacken. Dass klar wird, was sich genau dahinter verbirgt, gibts erstmal ein Beispiel.
Beispielangriff
Das Opfer ist bei facebook eingeloggt – was man ja sowieso als facebook-User quasi immer ist, auch wenn man nicht auf der Seite selbst unterwegs ist. Jetzt schickt der Angreifer dem Opfer einen durch einen URL-Shortener verschlüsselten Link zu, der aber in echt
http://www.facebook.com?deleteAccount=1
lautet und – zack, der Account ist futsch. Ist natürlich quatsch, die Jungs von facebook haben sich da schon Gedanken zu gemacht. Aber das Prinzip ist wohl klargeworden. Man kann sogar als Angreifer noch einen Schritt weitergehen und auf einer Webseite ein Bild einbinden, welches einen speziellen Link referenziert. Beispiel:
<img src="http://www.gmail.com?to=chef@firma.de&subject=Kündigung&text=Ich%20kündige!!!" />
„Kritische“ Anfragen nur per $_POST zuzulassen ist auch keine Lösung, denn ein Angreifer könnte in einem iframe einfach einen POST-Request in einer Form ausführen, der dann etwa wie folgt aussieht
<form action="http://www.facebook.com/profile.php" method="post"> <input name="deleteAccount" value="1" /> <input type="submit" /> </form> <script> document.forms[0].submit(); </script>
Auch ein Referrer-Check ist nicht zu empfehlen, weil damit evtl. Leute hinter Proxies ausgeschlossen werden. Außerdem könnte man per CURL den Referrer ja auch bequem faken.
Abwehrtechniken
So wirklich hilfreich ist eigentlich nur ein sogenanntes Shared-Secret bei gleichzeitiger, absoluter „XSS-Freiheit“ einer Webseite. Dazu gleich mehr. Wir erzeugen einen beliebigen, zufälligen String (=shared secret) und stecken ihn in die Session:
<?php $sharedsecret = md5(uniqid()); $_SESSION['sharedsecret'] = $sharedsecret; ?>
Weiterhin wird dieses Shared Secret in ein Hidden-Feld in der eigentlichen Form gesetzt:
<form action="validate.php" method="POST"> ... some fields... <input type="hidden" name="sharedsecret" value="<?php echo $sharedsecret; ?>" /> ... some fields... </form>
In der aufgerufenen validate.php wird nun gecheckt, ob das per $_POST übertragene Shared Secret gleich dem der Session ist. Ist dem nicht so, wurde eine CSRF-Attacke erkannt. Wie oben bereits erwähnt ist die Voraussetzung zum funktionieren dieser Technik eine absolute XSS-Freiheit der Webseite, denn wenn der Angreifer per eingeschleustem Javascript Zugriff auf die Seite hat, kann er auch das Hidden-Feld auslesen und gelangt auf diese Art und Weise dann doch wieder an das Shared Secret.
Update: Ich habe einen neuen Artikel veröffentlicht, der sich mit kreativen „Einsatzmöglichkeiten“ von CSRF befasst.
Update 2: Ich habe (mit Dank an Oliver aus den Kommentaren) ein sinnvolleres (weil funktionierendes) Beispiel gewählt.
Das ist zwar richtig, aber Dein Beispiel ist falsch. Mit CURL über PHP sendet Dein Server die Anfrage. :-)
Da ist mir in meinem Leichtsinn was entgangen, danke für die Klarstellung. Habs im Post entsprechend verbessert.