Sichern der REST-API, ohne das Rad neu zu erfinden

73

Ist es beim Entwerfen der REST-API üblich, zuerst einen Benutzer zu authentifizieren?

Der typische Anwendungsfall, den ich suche, ist:

  • Benutzer möchte Daten erhalten. Klar cool teilen wir gerne! Holen Sie sich einen öffentlichen API-Schlüssel und lesen Sie ihn weg!
  • Benutzer möchte Daten speichern / aktualisieren ... woah warte! Wer bist du, kannst du das tun?

Ich möchte es einmal erstellen und beispielsweise einer Web-App, einer Android-Anwendung oder einer iPhone-Anwendung erlauben, es zu verwenden.

Eine REST-API scheint bei solchen Anforderungen eine logische Wahl zu sein

Um meine Frage zu veranschaulichen, verwende ich ein einfaches Beispiel.

Ich habe ein Element in einer Datenbank, das ein Bewertungsattribut (Ganzzahl 1 bis 5) hat.

Wenn ich REST richtig verstehe, würde ich eine GET-Anfrage in der Sprache meiner Wahl implementieren, die csv, xml oder json wie folgt zurückgibt:

http://example.com/product/getrating/{id}/

Angenommen, wir wählen JSON aus und kehren zurück:

{
  "id": "1",
  "name": "widget1",
  "attributes": { "rating": {"type":"int", "value":4} }
}

Dies ist in Ordnung für öffentlich zugängliche APIs. Ich verstehe diesen Teil.

Ich habe unzählige Fragen, wie ich dies mit einem Sicherheitsmodell kombinieren kann. Ich bin an die Sicherheit von Web-Apps gewöhnt, bei denen ich einen Sitzungsstatus habe, der meinen Benutzer jederzeit identifiziert, damit ich steuern kann, was er tun kann, unabhängig davon, was er mir sendet. Soweit ich weiß, ist dies nicht RESTful, daher wäre dies in diesem Fall eine schlechte Lösung.

Ich werde versuchen, ein anderes Beispiel mit demselben Artikel / derselben Bewertung zu verwenden.

Wenn Benutzer "JOE" einem Artikel eine Bewertung hinzufügen möchte

Dies könnte geschehen mit:

http://example.com/product/addrating/{id}/{givenRating}/

An dieser Stelle möchte ich die Daten speichern, die besagen, dass "JOE" dem Produkt {id} eine Bewertung von {GivenRating} gegeben hat.

Frage: Woher weiß ich, dass die Anfrage von "JOE" und nicht von "BOB" kam?

Was wäre, wenn es sich um sinnvollere Daten wie die Telefonnummer eines Benutzers handeln würde?

Was ich bisher habe ist:

1) Verwenden Sie die integrierte Funktion von HTTP, um sich bei jeder Anforderung zu authentifizieren, entweder bei einfachem HTTP oder bei HTTPS.

Dies bedeutet, dass jede Anfrage jetzt die Form hat:

https://joe:[email protected]/product/addrating/{id}/{givenRating}/

2) Verwenden Sie einen Ansatz wie Amazon S3 mit privatem und öffentlichem Schlüssel: http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/

3) Verwenden Sie trotzdem ein Cookie und brechen Sie den zustandslosen Teil von REST.

Der zweite Ansatz erscheint mir besser, aber ich frage mich, ob ich das Ganze wirklich neu erfinden muss. Hashing, Speichern, Generieren der Schlüssel usw. ganz alleine?

Das klingt sehr nach der Verwendung einer Sitzung in einer typischen Webanwendung und dem Umschreiben des gesamten Stapels selbst, was für mich normalerweise bedeutet, dass Sie es falsch machen, insbesondere wenn es um Sicherheit geht.

EDIT: Ich denke, ich hätte auch OAuth erwähnen sollen.

jfrobishow
quelle
4
Wenn Sie bei jeder Anfrage den Benutzernamen und das Passwort senden, verwenden Sie HTTPS .
Matt Ball
52
Nichts mit Sicherheit zu tun, aber eine RESTful API nicht verwenden , getratingund andrating; Es wäre einfach so rating, und Sie würden zu dieser Ressource GET, POST, PUT oder DELETE gelangen.
Duncan

Antworten:

21

5 Jahre später bearbeiten

Verwenden Sie OAuth2!

Vorherige Version

Nein, es ist absolut nicht erforderlich, ein Cookie zu verwenden. Es ist nicht halb so sicher wie HTTP Digest, OAuth oder Amazon AWS (das nicht schwer zu kopieren ist).

Die Art und Weise, wie Sie ein Cookie betrachten sollten, ist, dass es ein Authentifizierungstoken ist, genauso wie Basic / Digest / OAuth /, was auch immer, aber weniger geeignet ist.

Ich bin jedoch nicht der Meinung, dass die Verwendung eines Cookies per se gegen die RESTful-Prinzipien verstößt, solange der Inhalt des Sitzungscookies keinen Einfluss auf den Inhalt der Ressource hat, die Sie vom Server zurückgeben.

Cookies sind böse, verwenden Sie sie nicht mehr.

Evert
quelle
2
Ich finde es nicht schwierig, Amazon zu kopieren ... wie ich es nicht "schwer" finde, JavaScript von Grund auf neu zu schreiben, aber jQuery hilft sicher dabei, es gut zu schreiben. Als ich darüber las, fragte ich mich, ob es keinen Rahmen gibt, um dies zu abstrahieren.
jfrobishow
1
Google es. Ich habe eine Implementierung für AWS geschrieben, aber ich glaube, sie ist nicht vollständig: code.google.com/p/sabredav/source/browse/lib/Sabre/HTTP/…
Evert
2
Entschuldigung, aber die Antwort ist nicht korrekt. Cookies und HTTP Digest sind komplementär, aber orthogonal. Mit der zweiten Option können Sie den Benutzer authentifizieren und ein Cookie ausgeben. Im Vergleich zu OAuth funktioniert die Cookie-basierte Sicherheit nicht, wenn Sie domänenübergreifende Dienste haben oder wenn Sie anderen nicht vertrauenswürdigen Personen erlauben, einen Client an Ihren Dienst zu schreiben (Dritte beteiligt), und Ihren Benutzern erlauben möchten, den Anwendungszugriff zu widerrufen. In anderen Fällen funktioniert es jedoch genau wie OAuth. Sie können sich ein Cookie als OAuth-Zugriffstoken vorstellen, das Sie übrigens auch irgendwo speichern müssen.
Zihotki
Meine Antwort wurde vor OAuth2 geschrieben, als jedes OAuth-Token eine Zusammenfassung einer Reihe von Informationen im Zusammenhang mit der Anfrage war. Dies gilt nicht für einen OAuth2-Träger, was ihn in der Tat einem Token in einem Cookie ziemlich gleichstellt.
Evert
21

Mach dir keine Sorgen um "RESTful", mach dir keine Sorgen um die Sicherheit. So mache ich das:

Schritt 1: Benutzer trifft Authentifizierungsdienst mit Anmeldeinformationen.

Schritt 2: Wenn Anmeldeinformationen ausgecheckt werden, geben Sie einen Fingerabdruck, eine Sitzungs-ID usw. zurück und speichern Sie sie zum späteren schnellen Abrufen im gemeinsam genutzten Speicher oder verwenden Sie eine Datenbank, wenn Sie nichts dagegen haben, Ihrer Webdienst-Bearbeitungszeit einige Millisekunden hinzuzufügen .

Schritt 3: Fügen Sie oben in jedem Webdienstskript einen Einstiegspunktaufruf hinzu, der den Fingerabdruck und die Sitzungs-ID für jede Webdienstanforderung überprüft.

Schritt 4: Wenn der Fingerabdruck und die Sitzungs-ID nicht gültig sind oder die Umleitung zur Authentifizierung abgelaufen ist.

LESEN SIE DIES:

RESTful Authentifizierung

Daniel Pereira
quelle
3
Aber zwingen Sie den Benutzer dann nicht, sich jedes Mal anzumelden, bevor Sie auf eine API zugreifen, wenn die "Sitzung" abläuft? Was machen Sie bei einem mobilen Gerät? Geben Sie ihnen einen permanenten "Schlüssel", damit sie sich nicht jedes Mal anmelden müssen, wenn sie die Anwendung verwenden. Verwenden Sie die API.
jfrobishow
1
Ich zwinge sie, sich anzumelden. Entweder das oder sie verwenden ein Cookie oder sie ordnen den Fingerabdruck ihrer UDID zu, aber die UDID bedeutet, dass der Benutzer von demselben Gerät aus auf den Dienst zugreifen muss.
Daniel Pereira
In Bezug auf Schritt 3 bedeutet dies, dass ich, wenn ich ein MVC-Framework verwende, das "Aktionen" in "Controllern" verwendet, in jede Aktion zwei zusätzliche Parameter (Fingerabdruck und Sitzungs-ID) eingeben sollte.
Sport
@sports Informationen zum Hinzufügen von Funktionen zu Beginn von Methodenaufrufen: Wenn Sie MVC / WebApi verwenden, fangen Sie Aktionen mit OWIN ab. Wenn Sie etwas durch den Endpunkt zulassen möchten, aber stattdessen die Domänenlogik sichern möchten, verwenden Sie AOP wie PostSharp. Wenn Sie Ihre eigenen rollen, verwenden Sie einfach Attribute und brechen Sie eine Reihe von Prinzipien, um Attribute in Attribute für Methoden zu integrieren, die Sie sichern möchten.
Suamere
8

3 Jahre später bearbeiten

Ich stimme Evert voll und ganz zu, verwende OAuth2 mit HTTPS und erfinde das Rad nicht neu! :-)

Durch einfachere REST-APIs - nicht für Clients von Drittanbietern gedacht - können JSON-Web-Token auch gut sein.

Vorherige Version

Verwenden Sie trotzdem einen Cookie und brechen Sie den zustandslosen Teil von REST.

Verwenden Sie keine Sitzungen. Bei Sitzungen ist Ihr REST-Service nicht gut skalierbar. Hier gibt es zwei Status: Anwendungsstatus (oder Clientstatus oder Sitzungen) und Ressourcenstatus. Der Anwendungsstatus enthält die Sitzungsdaten und wird vom REST-Client verwaltet. Der Ressourcenstatus enthält die Ressourceneigenschaften und -beziehungen und wird vom REST-Service verwaltet. Sie können ganz einfach entscheiden, ob eine bestimmte Variable Teil des Anwendungsstatus oder des Ressourcenstatus ist. Wenn die Datenmenge mit der Anzahl der aktiven Sitzungen zunimmt, gehört sie zum Anwendungsstatus. So gehört beispielsweise die Benutzeridentität der aktuellen Sitzung zum Anwendungsstatus, die Liste der Benutzer oder Benutzerberechtigungen zum Ressourcenstatus.

Der REST-Client sollte daher die Identifikationsfaktoren speichern und bei jeder Anfrage senden. Verwechseln Sie den REST-Client nicht mit dem HTTP-Client. Sie sind nicht gleich. Der REST-Client kann sich auch auf der Serverseite befinden, wenn er Curl verwendet, oder er kann beispielsweise ein serverseitiges http-only-Cookie erstellen, das er über CORS mit dem REST-Service teilen kann. Das einzige, was zählt, ist, dass sich der REST-Service bei jeder Anforderung authentifizieren muss. Daher müssen Sie bei jeder Anforderung die Anmeldeinformationen (Benutzername, Kennwort) senden.

  • Wenn Sie einen clientseitigen REST-Client schreiben, kann dies mit SSL + HTTP-Authentifizierung erfolgen. In diesem Fall können Sie einen credentials -> (identity, permissions)Cache auf dem Server erstellen , um die Authentifizierung zu beschleunigen. Beachten Sie, dass die Benutzer, wenn Sie diesen Cache leeren und dieselbe Anfrage senden, dieselbe Antwort erhalten, nur etwas länger. Sie können dies mit Sitzungen vergleichen: Wenn Sie den Sitzungsspeicher löschen, erhalten Benutzer eine status: 401 unauthorizedAntwort ...
  • Wenn Sie einen serverseitigen REST-Client schreiben und Identifikationsfaktoren über Curl an den REST-Service senden, haben Sie zwei Möglichkeiten. Sie können auch http auth verwenden oder einen Sitzungsmanager in Ihrem REST-Client verwenden, jedoch nicht im REST-Service.
  • Wenn jemand, dem nicht vertraut wird, Ihren REST-Client schreibt, müssen Sie eine Anwendung schreiben, um die Benutzer zu authentifizieren und ihnen die Verfügbarkeit zu geben, um zu entscheiden, ob sie verschiedenen Clients Berechtigungen erteilen möchten oder nicht. Oauth ist dafür bereits eine Lösung. Oauth1 ist sicherer, oauth2 ist weniger sicher, aber einfacher, und ich denke, es gibt mehrere andere Lösungen für dieses Problem ... Sie müssen dies nicht neu erfinden. Es gibt vollständige Authentifizierungs- und Autorisierungslösungen mit oauth, zum Beispiel: den wso-Identitätsserver .

Cookies sind nicht unbedingt schlecht. Sie können sie auf RESTful-Weise verwenden, bis sie den Clientstatus und der Service nur den Ressourcenstatus enthalten. Zum Beispiel können Sie den Warenkorb oder die bevorzugten Paginierungseinstellungen in Cookies speichern ...

inf3rno
quelle
1
Wie ist das nicht oben auf der Don't worry about being "RESTful", worry about security.Antwort?
Dennis Braga
Es ist zu spät und ich weiß nicht, wovon Sie sprechen, sorry. : D Ich werde diesen Beitrag morgen lesen, ich erinnere mich nicht daran ...
inf3rno
2
Ich habe es geschafft, den Beitrag noch einmal zu lesen. Yepp, ich denke, das liegt daran, dass mein Beitrag im Vergleich zu dem von Ihnen erwähnten Beitrag eine Verzögerung von 2 Jahren hat. Das ist alles, einen schönen Abend! :-)
inf3rno
Ich versuche nur mehr zu verstehen. Was meinen Sie mit einem Drittanbieter? Wie ist JWT für sie unsicher? Vielen Dank.
Yaobin Dann