Ich entwickle mehrere Webservices und eine Handvoll Clients (Web-App, Mobile usw.), die über HTTP (s) mit diesen Services kommunizieren. Meine aktuelle Aufgabe besteht darin, eine Authentifizierungs- und Autorisierungslösung für das Produkt zu entwerfen. Ich habe mich entschieden, externe Identitätsanbieter wie Facebook, Google, Microsoft, Twitter und dergleichen für die Authentifizierung zu nutzen.
Ich versuche das Problem zu lösen: "Wenn eine Anfrage an meinen Server kommt, woher weiß ich, wer der Benutzer ist und wie kann ich sicher sein?". Weitere Fragen weiter unten ...
Das System sollte eine tokenbasierte Authentifizierung verwenden (im Gegensatz zu beispielsweise Cookies oder Basisauthentifizierung).
Ich bin der Meinung, dass dies die richtige Wahl für die Skalierung über mehrere Clients und Server hinweg ist, während eine lose Kopplung bereitgestellt wird.
Basierend auf meinem Verständnis der tokenbasierten Authentifizierung stelle ich mir den Workflow im Folgenden vor. Konzentrieren wir uns zunächst auf Facebook in einem Webbrowser . Ich gehe davon aus, dass andere externe Identitätsanbieter über ähnliche Funktionen verfügen sollten, die ich jedoch noch nicht bestätigt habe.
Beachten Sie, dass ich zum Zeitpunkt des Schreibens Folgendes von der Facebook-Anmeldeversion 2.2 ausführe
Ich stelle mir vor, dass die Schritte 5 bis 9 für nachfolgende Anfragen an den Server wiederholt werden (während das Zugriffstoken des Benutzers gültig ist - nicht abgelaufen, von der FB-Seite widerrufen, App-Berechtigungen geändert usw.).
Hier ist ein Diagramm, das Ihnen dabei hilft, die Schritte zu befolgen. Bitte haben Sie Verständnis dafür, dass dieses System keine einseitige Anwendung (SPA) ist . Die genannten Webdienste sind API-Endpunkte, die JSON-Daten im Wesentlichen an Clients zurückliefern. Sie liefern kein HTML/JS/CSS (mit Ausnahme der Web-Client-Server).
Gibt es zuallererst offensichtliche Lücken/Grubenstürze bei dem beschriebenen Ansatz, der auf meinem Vorwort und meinen Anforderungen basiert?
Ist eine ausgehende Anfrage an Facebook zur Überprüfung des Zugriffstokens (Schritte 6-8 oben) pro Clientanfrage erforderlich/empfohlen?
Ich weiß zumindest, dass ich das Zugriffstoken überprüfen muss, das von der Clientanforderung stammt. Der empfohlene Ansatz für spätere Überprüfungen nach dem ersten ist mir jedoch nicht bekannt. Wenn es typische Muster gibt, bin ich daran interessiert, davon zu hören. Ich verstehe, dass sie anwendungsabhängig sein können, basierend auf meinen Anforderungen. Ich weiß jedoch noch nicht, wonach ich suchen soll. Ich werde die Due Diligence durchführen, sobald ich eine Grundidee habe.
Zum Beispiel mögliche Gedanken:
Hash das Paar Zugriffstoken + Benutzer-ID nach Abschluss der ersten Überprüfung und speichern Sie es in einem verteilten Cache (auf den alle Webserver zugreifen können), dessen Ablauf dem Ablauf von Zugriffstoken entspricht. Bei nachfolgenden Anforderungen von den Clients wird das Paar Zugriffstoken + Benutzer-ID gehasht und überprüft, ob es im Cache vorhanden ist. Falls vorhanden, wird die Anforderung autorisiert. Andernfalls wenden Sie sich an die Facebook-Grafik-API, um das Zugriffstoken zu bestätigen. Ich gehe davon aus, dass diese Strategie durchführbar ist, wenn ich HTTPS verwende (was ich auch sein werde). Wie aber ist die Leistung zu vergleichen?
Die akzeptierte Antwort in diese StackOverflow-Frage empfiehlt, ein benutzerdefiniertes Zugriffstoken zu erstellen, nachdem die erste Überprüfung des Facebook-Benutzertokens abgeschlossen ist. Das benutzerdefinierte Token wird dann für nachfolgende Anforderungen an den Client gesendet. Ich frage mich jedoch, ob dies komplexer ist als die obige Lösung. Dies würde die Implementierung eines eigenen Identitätsanbieters erfordern (etwas, das ich vermeiden möchte, weil ich in erster Linie externe Identitätsanbieter verwenden möchte…). Gibt es irgendeinen Grund für diesen Vorschlag?
Befindet sich das Feld "signedRequest" in der Antwort in Schritt 3 oben (erwähnt hier ), das dem signierten Anforderungsparameter hier im Anmeldefluss für Spiele entspricht?
Sie scheinen als gleichwertig zu gelten, da die ersteren in der Dokumentation auf die letzteren verweisen. Ich bin jedoch überrascht, dass die auf der Spieleseite erwähnte Verifizierungsstrategie im Abschnitt "Manuelles Erstellen eines Anmeldeflusses" Seite der Webdokumentation nicht erwähnt wird.
Wenn die Antwort auf # 3 "Ja" lautet, kann dieselbe Strategie zur Identitätsbestätigung angewendet werden, bei der die Signatur decodiert und mit der erwarteten Verwendung auf der Serverseite verglichen wird?
Ich frage mich, ob dies genutzt werden kann, anstatt einen ausgehenden Aufruf der debug_token-Diagramm-API (Schritt 6 oben) zu tätigen, um das empfohlene Zugriffstoken zu bestätigen hier :
Natürlich müsste, um den Vergleich auf der Serverseite durchzuführen, der signierte Anfrageteil zusammen mit der Anfrage an den Server gesendet werden (Schritt 5 oben). Neben der Machbarkeit ohne Einbußen bei der Sicherheit frage ich mich, wie sich die Leistung im Vergleich zu ausgehenden Anrufen verhält.
Wenn ich schon dabei bin, in welchem Szenario/zu welchem Zweck würden Sie beispielsweise das Zugriffstoken eines Benutzers auf eine Datenbank beibehalten? Ich sehe kein Szenario, in dem ich dies tun müsste, kann jedoch etwas übersehen. Ich bin gespannt, ob einige häufige Szenarien darin bestehen könnten, einige Gedanken zu spark.
Vielen Dank!
Nach Ihrer Beschreibung würde ich vorschlagen, einen serverseitigen Anmeldefluss wie in beschrieben zu verwenden
damit befindet sich das Token bereits auf Ihrem Server und muss nicht vom Client übergeben werden. Wenn Sie nicht verschlüsselte Verbindungen verwenden, kann dies ein Sicherheitsrisiko darstellen (z. B. bei Man-in-the-Middle-Angriffen).
Die Schritte wären:
(1) Leute einloggen
Sie müssen die Berechtigung, die Sie von den Benutzern erhalten möchten, im Parameter scope
angeben. Die Anfrage kann einfach über einen normalen Link ausgelöst werden:
GET https://www.facebook.com/dialog/oauth?
client_id={app-id}
&redirect_uri={redirect-uri}
&response_type=code
&scope={permission_list}
Sehen
(2) Bestätigen Sie die Identität
GET https://graph.facebook.com/oauth/access_token?
client_id={app-id}
&redirect_uri={redirect-uri}
&client_secret={app-secret}
&code={code-parameter}
(3) Überprüfen Sie das Zugriffstoken
Sie können den Token, wie Sie bereits in Ihrer Frage gesagt haben, über einsehen
GET /debug_token?input_token={token-to-inspect}
&access_token={app-token-or-admin-token}
Dies sollte nur serverseitig erfolgen, da Sie sonst Ihr App-Zugriffstoken für Endbenutzer sichtbar machen würden (keine gute Idee!).
Sehen
(4) Erweiterung des Zugriffstokens
Sobald Sie den (kurzlebigen) Token erhalten haben, können Sie einen Anruf tätigen, um den Token wie in beschrieben zu erweitern
wie die folgenden:
GET /oauth/access_token?grant_type=fb_exchange_token
&client_id={app-id}
&client_secret={app-secret}
&fb_exchange_token={short-lived-token}
(5) Speichern von Zugriffstoken
In Bezug auf das Speichern der Token auf dem Server schlägt FB vor, dies zu tun:
(6) Behandlung abgelaufener Zugriffstoken
Da FB Sie nicht benachrichtigt, wenn ein Token abgelaufen ist (und wenn Sie das Ablaufdatum nicht speichern und es mit dem aktuellen Zeitstempel vergleichen, bevor Sie einen Anruf tätigen), ist es möglich, dass Sie Fehlermeldungen von FB erhalten, wenn das Token ungültig wurde (nach max. 60 Tagen). Der Fehlercode lautet 190
:
{
"error": {
"message": "Error validating access token: Session has expired at unix
time SOME_TIME. The current unix time is SOME_TIME.",
"type": "OAuthException",
"code": 190
}
}
Sehen
Wenn das Zugriffstoken ungültig wird, muss sich die Person erneut anmelden. Anschließend können Sie erneut API-Aufrufe für sie durchführen. Der Login-Flow, den Ihre App für neue Benutzer verwendet, sollte bestimmen, welche Methode Sie anwenden müssen.
In der akzeptierten Antwort in dieser StackOverflow-Frage wird empfohlen, ein benutzerdefiniertes Zugriffstoken zu erstellen, nachdem die erste Überprüfung des Facebook-Benutzertokens abgeschlossen ist. Das benutzerdefinierte Token wird dann für nachfolgende Anforderungen an den Client gesendet. Ich frage mich jedoch, ob dies komplexer ist als die obige Lösung. Dies würde die Implementierung eines eigenen Identitätsanbieters erfordern (etwas, das ich vermeiden möchte, weil ich in erster Linie externe Identitätsanbieter verwenden möchte…). Gibt es irgendeinen Grund für diesen Vorschlag?
IMHO ist der richtige Weg. Ich würde https://jwt.io/ verwenden, mit dem Sie Werte (z. B. die Benutzer-ID) mit einem geheimen Schlüssel verschlüsseln können. Dann hängt Ihr Client dieses Token an jede Anfrage an. So können Sie die Anfrage überprüfen, ohne sie an Dritte weitergeben zu müssen (Sie benötigen auch keine Datenbankabfragen). Das Schöne dabei ist, dass Sie das Token nicht in Ihrer DB speichern müssen.
Sie können ein Ablaufdatum für das Token definieren, um zu erzwingen, dass sich der Client bei der dritten Partei erneut authentifiziert, wenn Sie dies möchten.
(Ich kann nicht mit den 3 und 4 Fragen helfen, sorry).