Sichere Java-Webanwendungen, Teil 2: Cross-Site Request Forgery

Know-how  –  4 Kommentare

Eine durch Cross-Site Request Forgery (CSRF) verwundbare Webanwendung ermöglicht es dem Angreifer, einem Benutzer heimlich Requests unterzuschieben und sie von ihm ausführen zu lassen. Die Protokolle der Webanwendung enthalten dabei gewöhnlich keinen Hinweis auf einen erfolgten Angriff.

Normalerweise sind bei einer Webanwendung ankommende Requests – ob nun GET oder POST ist irrelevant – vom jeweiligen Benutzer willentlich ausgelöst: Ein Klick auf "Set Administrator" zum Upgrade des ausgewählten Benutzers in die Gruppe der Administratoren, das Ausfüllen des Formulars zum Anlegen eines neuen Nutzers oder beliebige andere Aktionen, die der korrekt authentifizierte und autorisierte Anwender im Browser auslöst.

Damit der Benutzer (bzw. der zuvor erwähnte Administrator) derartige Operationen durchführen darf, muss er sich zunächst bei der Webanwendung anmelden. Bei korrektem Benutzernamen und Passwort erhält er anschließend eine Session-ID. In Java heißt der entsprechende Parameter standardmäßig JSESSIONID und hat beispielsweise den zufälligen Wert 55F770CDC57C3F396FA66D376FE643B4. Dieser wird meist im ebenfalls JSESSIONID genannten Cookie gespeichert – hin und wieder allerdings auch als URL-Parameter. Damit das Backend der Webanwendung den Benutzer wiedererkennt (HTTP ist schließlich zustandslos), überträgt der Browser die Session-Informationen bei jedem Request automatisch ans Backend.

Diesen Umstand nutzt ein Angreifer aus und präpariert eine spezielle Webseite zum Angriff auf die ausgewählte Webanwendung. Die erstellte Seite, etwa ein Forum oder ein Blog, ist unter einer beliebigen Domain erreichbar, und muss sich nicht auf dem Server der als Ziel ausgewählten Webanwendung befinden. Um Nutzer auf das Webangebot des Angreifers zu locken, kommen häufig Formen des Social Engineering zur Anwendung. Ein Beispiel hierfür ist ein Forum, in dem Probleme der anzugreifenden Webanwendung diskutiert werden. Benutzer, vor allem aber Administratoren, will man durch derartige Inhalte zum Besuch der Angreifer-Website verleiten. In deren HTML-Code enthalten ist zum Beispiel ein per JavaScript mit XmlHttpRequest (XHR) automatisch beim Laden ausgeführter POST-Request, mit dem die Anwendung einen neuen Benutzer anlegt:

<script type="text/javascript">
function sendForm() {
var request = new XMLHttpRequest();
request.open("POST",
"http://www.site.com/admin/AdminServlet");
request.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
request.send("userid=1234&username=
Webadmin&password=Webadmin1&active=true");
}
</script>

Die bekannte Same-Origin Policy verhindert hier nur, dass die Anwendung eine Response zum Request zurückliefert. Das Auslösen des Requests über Domaingrenzen hinweg ist dagegen problemlos möglich. Da der Angreifer bei einem CSRF-Angriff aber ohnehin nicht an einer Antwort der Webanwendung interessiert ist, stört solch eine Einschränkung nicht weiter.

Eine weitere Seite (idealerweise eine Folgeseite) präpariert der Angreifer mit einem simplen GET-Request, mit dem der zuvor angelegte Benutzer in die Gruppe der Administratoren aufgenommen wird:

<img src="http://www.site.com/admin/AdminServlet
?userid=1234&group=admin" width="0" height="0">

Der Code ist deutlich einfacher als der erste Teil zum Anlegen des Benutzers und benötigt ausschließlich HTML. Der Browser zeigt dem Benutzer durch die jeweils auf 0 festgelegte Breite und Höhe kein Broken-Image an. Das Bild ist einfach unsichtbar.

Ein Besuch auf der vom Angreifer erstellten Webseite löst nun immer den XmlHttpRequest per JavaScript aus. Sofern der Besucher nicht bei der Webanwendung angemeldet ist, und damit nicht über eine gültige Session verfügt, bricht die Anwendung die Request-Verarbeitung ab. Zum Abbruch führt ebenfalls ein Besucher mit gültiger Session, der allerdings nicht zu der in dem Fall festgelegten Administratorengruppe gehört (d.h., er verfügt nicht über ausreichende Rechte). Bei einem Administrator wird der Request dagegen verarbeitet und der neue Benutzer angelegt. Ähnliches gilt für Besucher der zweiten Seite mit der versteckten Grafik: Sie führt beim Besuch die Zuordnung des neuen Benutzers zur Administratorengruppe durch.

Der ausgenutzte Administrator bekommt davon nichts mit. Auch in der Webanwendung deutet wenig auf einen Angriff hin. Die Logs enthalten gegebenenfalls den Hinweis, dass ein neuer Benutzer angelegt und der Administratorengruppe hinzugefügt wurde und welcher legitime Benutzer (Administrator) Auslöser des Vorgangs war.

Mangels Rückmeldung der Webanwendung kann der Angreifer den Erfolg seines Angriffs nur durch einen Anmeldeversuch mit dem durch das Skript angelegten Benutzer überprüfen. Eine direkte Response der Webanwendung erreicht ihn nie.

Je nach angegriffener Webanwendung lassen sich unterschiedlichste Operationen auslösen. Hier hängt es davon an, wie lange die Benutzerinformationen aus dem Cookie der Webanwendung genügen und wann sie die Eingabe des Benutzerpassworts vor dem Ausführen einer Operation erfordert. Neben dem Anlegen von Benutzern für spätere Angriffe können Angreifer beispielsweise auch Bestellungen auslösen oder Daten manipulieren. Lediglich der Datendiebstahl, wie er bei SQL Injections möglich ist, stellt keine Option dar, da die Anwendung keine Daten an den Angreifer zurückliefert.

Noch gefährlicher ist ein Angriff mit CSRF allerdings dadurch, dass er sich als Türöffner ins Intranet verwenden lässt. Der Angreifer nutzt dazu einen dort angemeldeten Benutzer (zum Beispiel per VPN oder im LAN/WLAN des Unternehmens). Beim Besuch der präparierten Webseite führt der Browser des Benutzers die Requests ins Intranet durch. Eine gewöhnliche Firewall kann den Angriff nicht aufhalten, lediglich mit einer speziellen und korrekt konfigurierten Web Application Firewall würde der Request gestoppt. Dass solche per CSRF durchgeführte Angriffe immer noch weit verbreitet sind, zeigt etwa deren Platz 8 in den aktuellen OWASP Top 10. Höchste Zeit also, etwas gegen diese Bedrohung zu unternehmen.

Die beiden Anfangsbeispiele haben gezeigt, dass ein Angreifer zwei Dinge für einen Angriff per CSRF wissen muss: Die URL, an die der Request zu schicken ist, und die dabei notwendigen Parameter. Bei Anwendungen im Internet lassen sich derartige Informationen meist vergleichsweise einfach in Erfahrung bringen. Der Angreifer kann sich hierzu häufig selbst einen Standardaccount anlegen und so die Anwendung ausspionieren. Webanwendungen im Intranet eines Unternehmens erhöhen den Spionageaufwand. Hier fällt die Recherche bei Standardanwendungen wiederum leichter als bei Individualsoftware. Hundertprozentigen Schutz bietet eine Geheimhaltung allerdings nicht. Ex-Mitarbeiter, externe Entwickler und andere Informationsquellen könnten die notwendigen Daten verraten. Als Webentwickler muss man daher stärkere Geschütze gegen die CSRF-Bedrohung auffahren und Webanwendungen unabhängig ihres Einsatzortes vor CSRF schützen.

Wie eingangs gezeigt, lassen sich auch POST-Requests per CSRF auslösen. Allerdings ist der Aufwand dafür höher. Gleichzeitig halten sich Entwickler so ans REST-Paradigma, wonach GET-Requests keine Zustandsveränderung im Backend auslösen und lediglich Informationen zurückliefern dürfen. Wo immer Formulare zum Datenversand verwendet werden und im Backend eine Verarbeitung auslösen, sollte daher die POST-Methode zum Einsatz kommen:

<form method="POST" action="AdminServlet">
<!-- ... -->
</form>