Claims Management
Als nächstes müssen wir uns Gedanken über Claims machen. Ein Claim ist einfach das Name/Wert-Paar, das in unsere Access- und ID-Tokens eingebettet ist. Zum Beispiel könnten Sie einen user_id- oder E-Mail-Claim haben, damit nachgelagerte Anwendungen diese verwenden können, um Profile zu erstellen oder Entscheidungen zu treffen. Der verwirrende Teil ist, dass die OAuth Core-Spezifikation das Konzept der Claims nicht einführt oder sogar das Wort Claim enthält. Das ist nützlich, weil wir definieren können, was wir brauchen. Leider besteht die Herausforderung darin, dass die Leute sie definieren werden, wie sie es brauchen. Die JWT-Spezifikation (RFC 7519) führt das Konzept ein und definiert eine grundlegende Struktur, legt aber immer noch keine Konventionen für Namen, Strukturen usw. fest.
Die Verwendung von OpenID Connect schützt uns ziemlich gut. Es definiert einen einfachen Satz von Ansprüchen für Benutzerdetails wie Name, Adresse und ähnliches. Wenn wir nur diese verwenden und den Zugriff auf die richtigen Bereiche beschränken, weiß der Benutzer, welche Informationen er freigibt, und die Anwendungen wissen, wie sie diese verwenden können.
Alternativ dazu ist es der natürliche Wunsch, eine eindeutige Benutzerkennung zu haben, wenn wir zusätzliche Ansprüche hinzufügen. Wenn wir darüber nachdenken, verwenden wir einen verschleierten Primärschlüssel, der außerhalb unseres Systems keine Bedeutung hat. Wenn wir nicht aufpassen, könnte das ein Kundenidentifikator, eine Mitarbeiternummer oder sogar eine Sozialversicherungsnummer sein. Das ist die gleiche Situation, in der Facebook mit den Auswirkungen der Freigabe von zu vielen Informationen über das Netzwerk eines Benutzers über seine API kämpft.
Wir müssen nachdenklich sein und die Konsequenzen der Informationen bedenken, die wir in unsere Token aufnehmen. Wir sollten niemals Daten „nur für den Fall“ aufnehmen und stattdessen auf bestimmte Anwendungsfälle warten, die wir unterstützen wollen. Alles andere ist im besten Fall riskant und im schlimmsten Fall unverantwortlich.
Grant Types – When and Why
Während ich mich direkt auf Scopes und Claims gestürzt habe, hängt der andere häufigste Fehler mit den spezifischen OAuth-Grant-Typen oder Flows zusammen. Die vier Grant-Typen – Authorization Code, Implicit, Resource Owner Password und Client Credential – definieren, wie eine Anwendung Token von Ihrem OAuth-Server abrufen kann und werden in unterschiedlichen Anwendungsfällen verwendet.
Authorization Code
Der Flow Authorization Code ist standardmäßig der mächtigste und sicherste. Wenn die Anwendung den Benutzer zur Authentifizierung an den Identity Provider weiterleitet, gibt der IdP einen kurzlebigen, einmalig zu verwendenden Autorisierungscode zurück. Die Anwendung verwendet den Autorisierungscode, um das Access Token abzurufen.
Der wichtige Teil ist zweifach: Erstens, wenn der Benutzer den Autorisierungscode sieht, ist er bereits verbraucht und kann daher nicht mehr verwendet werden. Zweitens wird das Access Token von der Anwendung im Backend aufbewahrt. Unter der Annahme, dass die Anwendung sicher aufgebaut ist, muss ein böswilliger Benutzer einen anderen Weg finden, um sie anzugreifen.
Leider funktioniert dies nicht für clientseitige Anwendungen wie viele Javascript-Apps oder die meisten mobilen Apps, da die Anwendung selbst angegriffen oder dekompiliert werden kann, um sensible Informationen zu erhalten. Daher benötigen wir einen anderen Ansatz.
Implicit
Der Implicit-Flow wurde speziell für mobile Apps oder clientseitige Javascript-Apps entwickelt, bei denen eingebettete Anmeldeinformationen kompromittiert werden könnten. Die Mechanik ist insofern einfach, als dass die Anwendung den Benutzer zur Authentifizierung an den Identity Provider weiterleitet, der IdP gibt Token zurück, und die Anwendung verwendet sie entsprechend ihrer Scopes.
Da es sehr wahrscheinlich ist, dass der Benutzer mit den Token interagieren könnte, ist es wichtig, dass unsere Anwendungsfälle dies widerspiegeln. Wenn wir eine Banking-App haben, kann es eine schlechte Idee sein, den Bereich send_wire_transfers_to_russia zuzulassen, es sei denn, wir haben zusätzliche Faktoren in unseren Authentifizierungsprozess eingebaut, um zu überprüfen, dass der richtige Benutzer ihn benutzt. Das nächste Mal, wenn Sie Ihr Telefon verlieren, werden Sie das zu schätzen wissen.
Dies wird daher oft für OpenID Connect-Szenarien verwendet, in denen ein Benutzer vertrauenswürdige Profilinformationen an einen Dritten weitergeben möchte, aber nicht unbedingt Zugriff oder Berechtigungen für andere Systeme. Da die zugrundeliegenden Konzepte die gleichen sind und die Implementierung sehr ähnlich aussieht, bietet es den meisten Nutzen für den gleichen Aufwand.
Resource Owner Password
Im Vergleich zu den vorherigen Grant-Typen macht mich Resource Owner Password nervös. Sowohl beim Authorization Code als auch beim Implicit Flow leitet die Anwendung den Benutzer an den Identity Provider weiter, um seinen Benutzernamen und sein Passwort zu übermitteln. Infolgedessen sieht die Anwendung niemals die Anmeldeinformationen. Mit dem Resource Owner Password Flow nimmt die Anwendung selbst die Anmeldeinformationen an und übermittelt sie im Namen des Benutzers.
Wenn die Anwendung bösartig oder auch nur schlecht entwickelt ist, könnte sie diese Anmeldeinformationen speichern und die Informationen des Benutzers gefährden. Daher sollten Sie dies nur verwenden, wenn Sie Anwendungen für Ihre Benutzer zur Interaktion mit Ihren Legacy-Systemen entwickeln. Zum Beispiel könnte eine Bank dies für ein internes Mitarbeiterportal implementieren.
Aber denken Sie daran: Im Grunde trainieren Sie die Benutzer, ihre Anmeldedaten in Anwendungen einzugeben, denen sie nicht vertrauen, was bestenfalls eine schlechte Angewohnheit und ein Sicherheitsrisiko ist.
Client Credential
Der Berechtigungstyp Client Credential ist ausschließlich für Backend-Server-zu-Server-Operationen gedacht. Stellen Sie sich das wie einen Benutzernamen und ein Passwort für einen Server vor. Konzeptionell ist es nicht weit davon entfernt, wie sich Ihre Anwendung mit anderen Backend-Systemen wie Ihrer Datenbank oder Twilio verbindet. Der Vorteil ist, dass Ihr OAuth-Anbieter Konfigurationsinformationen oder andere Details innerhalb des Tokens selbst zurückgeben kann.
Da kein Benutzer beteiligt ist, wird OpenID Connect nicht unterstützt.
Abschließend
Während sich dieser gesamte Beitrag mit OAuth beschäftigt hat, ist Ihnen wahrscheinlich aufgefallen, dass ich keinen Code eingefügt habe. Der Grund dafür ist einfach: Die Design-Entscheidungen sind immer noch wichtiger.
Wenn Ihre Geltungsbereiche zu weit gefasst sind oder Ihre Forderungen sensible Informationen beinhalten oder Sie den falschen Ablauf für die Umgebung implementieren, werden die besten Bibliotheken der Welt Sie nicht schützen. Die Daten Ihrer Benutzer werden kompromittiert, Ihre Anwendungen werden angreifbar und Ihr Unternehmen wird die Konsequenzen tragen. Wenn Sie dagegen die Anwendungsfälle für Ihre Software verstehen und wissen, was Ihre Benutzer erreichen wollen, wird Ihre Software besser und sicherer sein, und Sie können die „Es tut uns leid…“-E-Mails an Ihre Kunden einschränken.
Für weitere Lektüre
Von hier aus können wir uns weiter mit den Protokollen, einzelnen Bibliotheken oder großartigen Büchern zu diesem Thema beschäftigen. Wenn Sie verstehen wollen, wie die einzelnen RFCs zusammenpassen, sollten Sie sich das Buch OAuth2.0 Simplified von Aaron Parecki und seine dazugehörige Map of OAuth 2.0 Specs ansehen. Es ist mein „go to cheatsheet“ für Links zu den wichtigsten Specs und welche Specs was abdecken. All das hat mich zu meinem Leitfaden für Recommended Practices for API Access Management inspiriert, der gute Design- und Entwicklungsprinzipien für OAuth-Clients, Autorisierungsserver, API-Gateways und Ihre Anwendungen beschreibt.