Identifikation und Authentifikation in RESTful APIs
Ja, viele von euch (srsly?) haben sicher schon einmal ein (semi) RESTful API entwickelt. Ein haeufiges Problem ist herauszufinden, ob ein Aufruf auch durchgefuehrt werden darf. Das Problem besteht darin, dass wir es dabei mit einem zustandslosen Protokoll (RFC 2616) zu tun haben, also fallen die Elgamal- und Diffie-Hellman-Kryptosysteme aus.
Um nun festzustellen, ob die Person (bzw. eine Applikation, stellvertretend fuer eine Person), die die Anfrage sendet auch wirklich die Person ist, fuer die sie sich ausgibt (Identifikation) und um gleichzeitig festzustellen, ob die Anfrage nicht manipuliert wurde (Authentifikation), gibt es zum einen das freie OAuth Protokoll, was aber relativ kompliziert zu implementieren ist, und zum anderen gibt es aehnliche Ansaetze, wie zum Beispiel das Flickr Auth Protokoll. Beide Protokolle bieten ausserdem die Moeglichkeit externen Programmen (Clients) den Zugriff auf das System (Service Provider) zu authorisieren.
Sofern letzteres nicht noetig ist, reicht jedoch ein abgespecktes Protokoll, das dem Flickr Protokoll sehr nah kommt. Hierbei faellt der Aufwand der sicheren Schluesseluebertragung weg. Und so einfach kann es gehen:
- Der Service Provider generiert einen oeffentlichen Schluessel (API Key) und einen privaten Schluessel (Secret). Ich habe fuer den oeffentlichen Schluessel die SHA1 Pruefsumme verschiedener Variablen und fuer den privaten Schluessel die MD5 Pruefsumme von Variablen, Zufallszahlen und Timestamps genutzt.
- Der Client wird mit beiden Keys ausgestattet. Wie gesagt: Der unwiretapped Schluesselaustausch muss anders sichergestellt werden. Bei meinem System kann der Benutzer die Keys einsehen, wenn er sich zuvor mit seinen Zugangsdaten eingeloggt hat. Das ist auch gaengige Praxis.
- Bei einer Anfragegenerierung werden die Variablen inkl. oeffentlichem Schluessel (die Bezeichner, nicht die Werte!) alphabetisch sortiert und dann mit ihrem Wert konkateniert. Dann werden die Key-Value-Strings konkateniert und der private Schluessel wird vorangestellt. Das Ganze wird jetzt gehasht (e.g. MD5). Nun werden alle Variablen und die zusaetzlich generierte signature-Variable uebertragen.
- Der Service Provider empfaengt alle Variablen, nimmt davon den oeffentlichen Schluessel und sucht in seiner Datenbank nach dem dazu passenden privaten Schluessel. Jetzt kann der Service Provider das selbe Spiel spielen, das der Client schon durchgemacht hat: Variablen sortieren, Key-Value-Strings bauen, konkatenieren, den privaten Schluessel voranstellen und hashen. Der Vergleich der uebermittelten Signatur und der generierten Signatur erlaubt die Authentifizierung des Zugriffs.
Beispiel
Der API Key ist fd40e3589bbb58ec358122c5cd32fcc6481707bb, das Geheimnis ist 162c9d446beb754b804b904772ff87b6. Die Variablen sind (Bezeichner = Wert):
- method = deleteEntries
- rangeFrom = 99
- rangeTo = 101
Die Anfrage wird nun wie folgt Client-seitig generiert:
Sortieren:
apiKey vor method vor rangeFrom vor rangeTo
Konkatenieren:
apiKeyfd40e3589bbb58ec358122c5cd32fcc6481707bbmethoddeleteEntriesrangeFrom99rangeTo101
Private Key voranstellen:
162c9d446beb754b804b904772ff87b6apiKeyfd40e3589bbb58ec358122c5cd32fcc6481707bbmethoddeleteEntriesrangeFrom99rangeTo101
Hashen:
9ad5100448f0549472b0e70722aa06bb
Variablen fuer die Anfrage zusammensetzen:
http://example.com/rest/?apiKey=fd40e3589bbb58ec358122c5cd32fcc6481707bb&method=deleteEntries&rangeFrom=99&rangeTo=101&signature=9ad5100448f0549472b0e70722aa06bb
Das wird nun ausgefuehrt und auf der Service Provider Seite geht es dann so weiter:
API Key auslesen:
fd40e3589bbb58ec358122c5cd32fcc6481707bb
In der Datenbank nach dem passenden privaten Schluessel suchen:
162c9d446beb754b804b904772ff87b6
Sortieren, Konkatenieren, Private Key voranstellen, Hashen (s.o.):
9ad5100448f0549472b0e70722aa06bb
Ergebnisse vergleichen:
9ad5100448f0549472b0e70722aa06bb = 9ad5100448f0549472b0e70722aa06bb
That’s it. Ist sehr einfach zu implementieren und ist dafuer extrem sicher.







am 10. März 2010 um 13:35 Uhr.
Moment. Du generierst pro API-Nutzer einen API-Key und einen privaten Schl?ssel? Und warum kennen beide den privaten Schl?ssel?
am 10. März 2010 um 14:43 Uhr.
Der oeffentliche Schluessel ist dazu da den privaten Schluessel herauszufinden. Der private Schluessel ist das gemeinsame Geheimnis, was zur Signierung verwendet wird. Das ist keine PKI im eigentlichen Sinne! Der Service Provider hat die Faehigkeit zu signieren, aber da von ihm keine Anfragen ausgehen passiert das nicht. Um das System nicht mit einer PKI zu verwechseln sollte man vielleicht bei API Key und Secret bleiben statt bei oeffentlichem/privatem Schluessel.