REST- und Authentifizierungsvarianten

70

Ich arbeite derzeit an einer REST-Bibliothek für .net und würde gerne einige Meinungen zu einem offenen Punkt hören, den ich habe: REST und Authentifizierung.

Hier ist ein Beispiel für eine RESTful-Schnittstelle, die mit der Bibliothek verwendet wird:

[RestRoot("/user")]
public interface IUserInterface
{
  [RestPut("/")]
  void Add(User user);

  [RestGet("/")]
  int[] List();

  [RestGet("/get/{id}")]
  User Get(int id);

  [RestDelete("/delete/{id}")]
  void Delete(int id);
}

Der Servercode implementiert dann nur die Schnittstelle und die Clients können dieselbe Schnittstelle über eine Factory erhalten. Wenn der Client die Bibliothek nicht verwendet, funktioniert auch eine Standard-HTTP-Anforderung.

Ich weiß, dass es die wichtigsten Möglichkeiten gibt, entweder HTTP Basic Auth zu verwenden oder ein Token an Anforderungen zu senden, die authentifizierte Benutzer erfordern.

Die erste Methode (HTTP Basic Auth) weist die folgenden Probleme auf (teilweise Webbrowserspezifisch):

  • Das Passwort wird bei jeder Anfrage übertragen - auch bei SSL hat dies ein "schlechtes Gefühl".
  • Da das Passwort mit einem Anforderungsheader übertragen wird, kann ein lokaler Angreifer leicht auf die übertragenen Header schauen, um das Passwort zu erhalten.
  • Das Passwort ist im Speicher des Browsers verfügbar.
  • Keine Standardmethode zum Ablaufen von Benutzersitzungen.
  • Die Anmeldung mit einem Browser unterbricht das Erscheinungsbild einer Seite.

Die Probleme bei der zweiten Methode konzentrieren sich mehr auf die Implementierung und die Verwendung der Bibliothek:

  • Jeder Anforderungs-URI, der eine Authentifizierung benötigt, muss einen Parameter für das Token haben, der sich nur sehr wiederholt.
  • Es muss viel mehr Code geschrieben werden, wenn bei jeder Methodenimplementierung überprüft werden muss, ob ein Token gültig ist.
  • Die Schnittstelle wird weniger spezifisch, z . B. [RestGet("/get/{id}")]vs.[RestGet("/get/{id}/{token}")]
  • Wo soll der Token abgelegt werden: am Ende der URI? nach der Wurzel? irgendwo anders?

Meine Idee war, das Token als Parameter an die URL wie zu übergeben http:/server/user/get/1234?token=token_id.

Eine andere Möglichkeit wäre, den Parameter als HTTP-Header zu senden, aber dies würde die Verwendung mit einfachen HTTP-Clients erschweren, denke ich.

Das Token wird bei jeder Anforderung als benutzerdefinierter HTTP-Header ("X-Session-ID") an den Client zurückgegeben.

Dies könnte dann vollständig von der Schnittstelle abstrahiert werden, und jede Implementierung, die eine Authentifizierung benötigt, könnte nur fragen, zu welchem ​​Benutzer das Token (falls angegeben) gehört.

Glaubst du, dies würde REST zu sehr verletzen oder hast du bessere Ideen?

Fionn
quelle

Antworten:

64

Ich neige dazu zu glauben, dass Authentifizierungsdetails in den Header gehören, nicht in die URI. Wenn Sie sich darauf verlassen, dass ein Token auf dem URI platziert wird, muss jeder URI in Ihrer Anwendung codiert werden, um das Token einzuschließen. Dies würde sich auch negativ auf das Caching auswirken. Ressourcen mit einem sich ständig ändernden Token können nicht mehr zwischengespeichert werden. Ressourcenbezogene Informationen gehören in den URI, nicht anwendungsbezogene Daten wie Anmeldeinformationen.

Es scheint, dass Sie als Client auf Webbrowser abzielen müssen? In diesem Fall können Sie die Verwendung der HTTP Digest-Zugriffsauthentifizierung oder die Ausstellung eigener SSL-Zertifikate für Clients untersuchen, um diese eindeutig zu identifizieren und zu authentifizieren. Ich denke auch nicht, dass Sitzungscookies unbedingt eine schlechte Sache sind. Vor allem, wenn es um einen Browser geht. Solange Sie den Code für die Cookie-Behandlung isolieren und den Rest der Anwendung nicht darauf verlassen, ist alles in Ordnung. Der Schlüssel ist nur, die Identität des Benutzers in der Sitzung zu speichern, sonst nichts. Missbrauch des serverseitigen Sitzungsstatus nicht.

Wenn Sie andere Clients als den Browser ansprechen, können Sie verschiedene Ansätze verfolgen. Ich hatte Glück mit der Verwendung des S3-Authentifizierungsmechanismus von Amazon .

Das ist natürlich alles sehr subjektiv. Reinheit und das Befolgen von REST auf den Brief können manchmal unpraktisch sein. Solange Sie ein solches Verhalten minimieren und isolieren, kann der Kern Ihrer Anwendung immer noch REST-fähig sein. Ich empfehle RESTful Web Services als hervorragende Quelle für REST-Informationen und -Ansätze.

laz
quelle
Im S3-Beispiel teilen sie den kryptografischen Schlüssel mit Clients - das ist schlecht, nicht wahr?
Gill Bates
Wie bei jeder Art von gemeinsamer geheimer Kryptographie ist es wichtig, dass beide Parteien die Geheimhaltung des Schlüssels wahren. In dieser Hinsicht ist es nicht schlimmer als die symmetrische Kryptographie.
Laz
15

Ich stimme workmad3 zu. Wenn die Sitzungslebensdauer eingehalten werden muss, sollten Sie eine Sitzungsressource erstellen. Das Posten auf dieser Ressource mit Benutzeranmeldeinformationen (entweder Basisauthentifizierung oder Anmeldeinformationen im Hauptinhalt) gibt eine eindeutige Sitzungs-ID zurück. Durch Löschen in / session / {id} wird der Benutzer abgemeldet.

Wenn Sie die Ablaufzeit der Sitzung steuern möchten. Beim Erstellen einer neuen Sitzung (Post on Session Resource) setzt der Server ein Cookie für die Antwort (unter Verwendung des Standard-Set-Cookie-Headers). Der Cookie enthält eine Ablaufzeit. Die Cookie-Zeichenfolge sollte auf dem Server verschlüsselt sein, damit nur der Server dieses Cookie öffnen kann. Bei jeder nachfolgenden Anforderung an den Server wird das Sitzungscookie im Cookie-Header gesendet. (Dies wird automatisch für Sie erledigt, wenn Ihr Client ein Browser ist.) Der Server muss das Cookie für jede Anforderung "erneuern", dh ein neues Cookie mit einer neuen Ablaufzeit erstellen (Timeout der Sitzung verlängern). Denken Sie daran, das Cookie zu löschen, wenn der Benutzer delete für die Sitzungsressource aufruft.

Wenn Sie möchten, dass Ihre Anwendung sicherer ist, können Sie die Client-IP im Cookie selbst speichern. Wenn also eine Anforderung eingeht, kann der Server überprüfen, ob sie vom "ursprünglichen" Client gesendet wurde. Denken Sie jedoch daran, dass diese Lösung problematisch sein kann, wenn Proxys beteiligt sind, da der Server möglicherweise alle Anforderungen als vom selben Client stammend "sieht".

LiorH
quelle
Ich sehe hier kein Problem mit Proxys. Es ist nur so, dass die zusätzliche Sicherheit durch die Tatsache verringert wird, dass einige Clients gleich zu sein scheinen. Die Cookies sollten auch nur httpOn sein .
Maaartinus
4

Die Restauthentifizierung, die ich gesehen habe, behandelt die Sitzungen als REST-Ressource für die Erstellung, Zerstörung usw., und dann wird die Sitzungs-ID hin und her übergeben. Diejenigen, die ich gesehen habe, neigen dazu, das Sitzungscookie dafür zu verwenden, da dies die einzige Möglichkeit ist, es wirklich zu sichern. Wenn Sie die Sitzungs-ID in der URL übergeben, können Sie nicht wirklich authentifizieren, dass sie vom richtigen Client stammt.

Die Authentifizierung ist jedoch ein heikles Problem bei REST, da eine Form des Status außerhalb der URL aufbewahrt werden muss, was gegen die REST-Prinzipien verstößt, dass die URL alles ist, was zur Darstellung des Status erforderlich ist.

workmad3
quelle
Da SSL immer verwendet wird, wenn es nicht intern in einem gesicherten Netzwerk verwendet wird und UUIDs für Sitzungen verwendet werden, sollte es kein Problem sein, woher es stammt. Und was hindert jemanden daran, den Cookie zu fälschen?
Fionn
3
Ich würde nicht sagen, dass die URI alles ist, was zur Darstellung des Zustands erforderlich ist, ein Prinzip von REST. Es scheint vielmehr eine bessere Möglichkeit zu sein, Ressourcen adressierbar zu haben und den gesamten in der Anforderung enthaltenen Anwendungsstatus anzugeben.
Laz
Sie würden das Cookie mit einem MAC sichern, z. B. wenn der Server ein Geheimnis hat, und dem Client das folgende Sitzungstoken aushändigen: <sessionid> _ <mac> wobei mac als SHA1 konstruiert ist (<session_id> _ <secrect>) Wenn ein Client ein Token <session_id> _ <mac> sendet, muss der Server prüfen, ob <sessionid> _ <secret> gleich <mac> ist
Aufgabenwidrig
18
In diesen Diskussionen ist es wichtig, den Anwendungsstatus (Sitzungsstatus) vom Ressourcenstatus zu unterscheiden . In einer RESTful-Architektur wird der Ressourcenstatus serverseitig gespeichert, während der Anwendungsstatus clientseitig gespeichert wird. [ infoq.com/articles/mark-baker-hypermedia]
user359996
1
@maaartinus: Derzeit (da die Frage "vor einiger Zeit" gestellt wurde) würde ich nicht mehr in Betracht ziehen, Sitzungsdaten als Teil der URL zu verwenden. Dies schien zunächst logisch, aber auf den zweiten Blick sind die Risiken viel zu hoch.
Fionn