Wir schreiben das Jahr 2015. Wer heutzutage Software schreibt, die nicht im Internet sichtbar ist, der hat auch noch ein Telefon mit Wählscheibe. Na gut, das ist jetzt vielleicht ein bisschen übertrieben… aber doch schon sehr nah an der Wahrheit. Millionen von Web Services werden weltweit angeboten; viele davon mit scheunentorgroßen Sicherheitslücken. Das „Open Web Application Security Project“ (OWASP) führt eine Liste mit den zehn wichtigsten Sicherheitsrisiken im Netz, die OWASP Top Ten. In einem eintägigen Workshop Mitte April mit Tobias Glemser von Secuvera haben wir uns intensiv mit den Risiken beschäftigt, Angriffsszenarien durchgespielt und Gegenmaßnahmen besprochen. Fazit: Au Backe! Aus gegebenem Anlass möchte ich an dieser Stelle exemplarisch kurz auf Platz 8 der aktuellen Liste eingehen: Cross-Site Request Forgery (CSRF).
Cross-Site Request Forgery in a Nutshell
Es gibt im Netz genügend Material zu diesem Thema, so dass ich nicht in die Tiefe gehen werde. Daher hier CSRF in wenigen Sätzen. Man nehme eine populäre Website mit Schnittstelle (popularwebsitewithapi.io) bei der sich Nutzer anmelden können. In aller Regel wird beim Login eine Session erzeugt und auf dem Server persistiert. Der Nutzer bekommt einen Cookie mit einem Session-Schlüssel (z.B. PHPSESSID), den der Browser speichert. Wann immer jetzt der Nutzer eine URL auf dem Server aufruft sendet der Browser den Cookie mit. Der Server validiert so, dass es sich wirklich um den betreffenden Nutzer handelt. Wenn der Nutzer mit dem selben Browser auf einer anderen, eher zwielichtige Seite surft (evilwarezsite.de.vu) bekommt dieser Server den Cookie natürlich nicht. Aber er kann dem Nutzer Aufrufe der anderen Seite unterschieben, etwa indem die Seite „eine Bild lädt“:
<img src="https://popularwebsitewithapi.io/api/addcomment?content=Go+to+evilwarezsite.de.vu+-+they+are+the+bestest%21" class="hidden-img"/>
Wenn der Nutzer also die Seite evilwarezsite.de.vu ansurft schickt der Browser den entsprechenden Aufruf zum Laden des Bildes an popularwebsitewithapi.io. Der Browser sendet auch hier den Cookie mit der Session-ID mit und der Server führt im Namen des angemeldeten Nutzers den entsprechenden API-Aufruf durch. Schwupp-di-wupp steht dort eine Empfehlung an alle seine Freunde… Damit erlangt der Angreifer nicht die Kontrolle über die Session und erhält keine Informationen! Trotzdem kann er die Session und damit den Namen des Opfers missbrauchen um seine eigenen Ziele zu verfolgen.
Schutz gegen CSRF
Als Schutz gegen CSRF dient eine zweite Information, die nicht automatisch zum Server geschickt wird und die zur Session passen muss. Die einfachste Variante ist ein zweiter Schlüssel, der aktiv bei jedem Request parallel zu Session-ID an den Server übergeben wird. Bei klassischen, auf dem Server gerenderten Webseiten kann dabei sogar für jeden Aufruf ein neuer Schlüssel, eine sogenannte Nonce, erzeugt werden. Wie Frank Pientka uns im Rahmen seines Vortrags am 22.04.2015 beim Java-Stammtisch in Göttingen vorgestellt hat, bietet Apache Tomcat hierfür ein fertiges Filter Valve namens CSRFPreventionFilter, das in der web.xml einfach aktiviert werden muss. Danach wird automatisch an jeden Link in einer ausgelieferten Seite, auf die das filter-mapping passt, der GET-Parameter CSRF_NONCE angehängt und der Wert in der Session gespeichert. Stimmen die Werte bei einem Aufruf nicht überein gibt es einen Fehler. Bei Web Applications wie z.B. Single Page Apps, die parallele, asynchrone Anfragen verwenden, kommt eine Nonce natürlich nicht in Frage. Statt dessen kann ein Token mit längerer Lebensdauer verwendet werden. Doch das sprengt jetzt die Nussschale.
Das Titelbild stammt von http://pixabay.com/de/matrix-erde-global-international-434036/ und steht unter CC0-Lizenz.
CSRF Filter scheint mir eine saubere Lösung die eigentlich mit jedem Framework funktionieren sollte. Danke für den informativen Artikel.