Autorisierungsdienste mit OAuth

Seite 3: Sicherheitsprobleme und Implementierung

Inhaltsverzeichnis

Wie heise Developer berichtete, gab es ein Sicherheitsproblem für das dreibeinige OAuth-Protokoll. Dabei ging es um das Ausnutzen des Anfrage-Tokens und der Session beim Autorisierungsprozess in OAuth (dreibeiniges Oauth-Protokoll Version 1.0, Sektion 6). Der Angreifer loggt sich in eine Konsumenten-Webanwendung ein und initiiert den Autorisierungsprozess zu einem Service-Provider. Statt jedoch den Prozess weiter durchzuspielen, speichert er den Anfrage-URI (Uniform Resource Identifier) inklusive des Anfrage-Tokens. Später versucht der Angreifer beispielsweise mit Phishing ein Opfer zu finden, das den Autorisierungsprozess mit dem gespeicherten Anfrage-URI aus dem gleichen Konsumenten weiterführt. Damit ermöglicht das Opfer dem Service-Provider einen Zugriff auf seine private Ressourcen.

Mit dem Klick auf den Anfrage-URI des Angreifers führt das Opfer den Autorisierungsprozess des Angreifers mit dem vom Konsument ausgestellten Anfrage-Token weiter. Das heißt, das Opfer würde gar nicht merken, dass ein Angriff stattgefunden hat. Nachdem es seine privaten Ressourcen beim Service-Provider freigegeben hat, kann der Angreifer den gespeicherten Anfrage-URI wieder ausführen. Er kann nun auf sämtliche vom Opfer freigegebenen Ressourcen zugreifen. Im Fall, dass der Angreifer ebenfalls ein Konto auf dem echten Konsumenten besitzt, wird der Zugriff für die zukünftigen Aktionen sogar gespeichert. Damals schlugen die von der Sicherheitslücke betroffenen Organisationen schnell eine Lösung vor, die die Endnutzer darüber informiert, dass eine Autorisierung aus einer unbekannten Quelle eine Gefahr darstellt und sie diese nicht durchführen sollten.

Derzeit existieren zwei OAuth-Bibliotheken für Java: zum einen die originale OAuth-Implementierung auf Google Code. Zum anderen findet man mit oauth-signpost eine Alternative, jedoch ausschließlich für Konsumenten beziehungsweise Konsumenten-Entwickler. Der Artikel widmet sich im Folgenden der originalen Bibliothek. Das dieser entnommene Beispiel zeigt ausschließlich dreibeinige Implementierungen, da sie aufwendiger als die zweibeinigen sind.

Zu Beginn ist ein einfacher Service-Provider aufzubauen. Anschließend erstellt man eine Konsumenten Anwendung, die auf den implementierten Service-Provider zugreift.

Die Quellcodes lassen sich hier als Eclipse-Workspace herunterladen. Folgende Voraussetzungen sind für die Beispiele wichtig:

README.txt

Die Servlet-Klasse SampleProviderConsumer dient als Konsumenten-Beispiel für den im nächsten Abschnitt beschriebenen Beispiel-Service-Provider. Die wichtigsten Punkte in der Klasse sind:

  • Die Methode doGet(...) in der Klasse SampleProviderConsumer wird aufgerufen, falls der Beispiel-Service-Provider in der Startseite des Konsumenten ausgewählt wird (http://localhost:9090/oauth-example-consumer/SampleProvider). Hier ist zu beachten, dass der Service-Provider keine persistente Speicherung der Session durchführt, sodass nach seinem Neustart eine neue Autorisierung – und gleichzeitig eine neue Authentifizierung – stattfinden muss.
  • In der Klasse CookieConsumer liest man die Konfiguration des Konsumenten-Geheimnisses ein. Zudem speichert man das Zugriffs-Token, das der Service-Provider zur Verfügung stellt. Die Klasse CookieConsumer lässt sich in der Methode doGet(...) der oben genannten Klasse verwenden.

Es sind drei wichtige Servlet-Klassen vorhanden, die die Anfrage eines Konsumenten bedienen sollten. Die wichtigsten Punkte der einzelnen Servlet-Klasse sind:

  • RequestTokenServlet (ein nicht bestätigter Anfrage-Token): Die Servlet-Klasse kümmert sich um das Anfrage-Token und das Konsumenten-Geheimnis.
  • AuthorizationServlet (ein bestätigter Anfrage-Token): Die Servlet-Klasse dient als Beispiel, wie die Authentifizierung und Autorisierung des Endnutzers stattfinden können. Falls er noch nicht authentifiziert und autorisiert ist, bietet man ihm eine einfache Login-Seite (authorize.jsp) an. Falls das bereits geschehen ist, wird der Endnutzer an die Konsumenten-Seite zurückgeleitet (über die Methode returnToConsumer).
  • AccessTokenServlet: Sie generiert den Zugriffs-Token und gibt ihn anschließend an die Konsumenten-Seite weiter.