GraphQL-Authentifizierung mit JSON Web Tokens

Blog

GraphQL-Authentifizierung mit JSON Web Tokens

Einführung

In diesem Tutorial besprechen wir die GraphQL-Authentifizierung mit JSON-Webtoken, die in den letzten Jahren die vorherrschende Methode zur Handhabung der Authentifizierung im Javascript-Ökosystem war. Wir werden uns auch das Konzept der Autorisierung ansehen, indem wir uns die Ansprüche ansehen.



Lass uns zuerst rübergehen Authentifizierung und Genehmigung im Kontext von Webanwendungen.

Was ist Authentifizierung?

Authentifizierung kann als eine Möglichkeit zur Überprüfung Ihrer Identität definiert werden. Eine Art der Authentifizierung könnte ein gültiger Lichtbildausweis sein: Die Tatsache, dass Sie wie die Person auf dem Foto aussehen und die Tatsache, dass der Ausweis nicht gefälscht zu sein scheint, authentifiziert, dass Sie die sind, für die Sie sich ausgeben. Bei Webanwendungen verlassen wir uns auf Benutzernamen und Passwörter. Wenn Sie Ihren Benutzernamen und ein Passwort eingeben, das idealerweise nur Ihnen bekannt ist, authentifizieren Sie sich, dass Sie Sie sind und erhalten Zugriff.



Was ist Autorisierung?

Wir können uns vorstellen Genehmigung wie die Richtlinien, wer Zugriff auf eine bestimmte Ressource hat. Wenn Sie beispielsweise ein Konzert als Zuschauer mit einem Ticket betreten, das Sie authentifiziert, sind Sie berechtigt, Zugang zum Veranstaltungsort, zu Ihrem Sitzplatz usw. zu haben; Aber als Bandmitglied hat man Zugang zu mehr Bereichen, wie Backstage und der Bühne selbst. Ein weiteres Beispiel wäre, wenn Sie sich bei einer Social-Media-Plattform anmelden, sind Sie berechtigt, Ihre eigenen Beiträge zu löschen, jedoch nicht die Beiträge anderer Benutzer. Andererseits ist ein Administrator dieser Social-Media-Plattform berechtigt, jeden der Beiträge zu löschen, unabhängig davon, welcher Benutzer ihn gepostet hat.

Artikelübersicht

In diesem Artikel werfen wir zunächst einen Blick auf die Authentifizierung, indem wir JSON-Webtoken untersuchen. Von dort aus werden wir uns die klassische Art der Sicherung traditioneller Web-APIs mit Middleware ansehen, dann das Wissen aus den vorherigen beiden Abschnitten übernehmen und auf GraphQL anwenden.



Wenn Sie nur an der Authentifizierung interessiert sind, müssen Sie die folgenden Abschnitte nicht lesen. Mit der Authentifizierung im Gepäck werden wir dann die Autorisierung untersuchen: wie sie in traditionellen REST-APIs verwendet wird und von dort aus auf eine GraphQL-API anwenden.

Voraussetzungen

In diesem Artikel wird ein grundlegendes Verständnis der folgenden Konzepte vorausgesetzt: Webserver in|_+_|, Middleware und |_+_|, ein GraphQL-Server.

Verstehen und Verwenden von JSON-Webtoken

Bevor wir uns mit der Anwendung von JSON-Webtoken (JWT) in GraphQL befassen, müssen wir verstehen, was sie sind.

JWTs werden nach einem offenen Standard erstellt, um eine eigenständige Möglichkeit zum sicheren Austausch von Daten als JSON-Objekt zu bieten. Um seine Informationen zu sichern, verwenden JWTs verschiedene Formen von Verschlüsselungsschemata. Sie können Ihre Informationen entweder sicher verschlüsseln (vorausgesetzt, Sie verwenden das richtige Geheimnis) oder eine private Verschlüsselung verwenden. Die Unterschiede zwischen den beiden sind nicht Gegenstand dieses Artikels, aber Sie können mehr über den Unterschied erfahren in Dieser Beitrag

JSON-Webtoken-Struktur

Der Aufbau eines JWT besteht aus drei Teilen:

die r-Programmierumgebung
  • Die Kopfzeile : Der Header enthält Metainformationen wie den Typ des Tokens und die für seinen Inhalt verwendete Signatur. Der Typ wäre normalerweise immer JWT. Die Signatur sagt uns, welcher Algorithmus zum Signieren des Tokens verwendet wurde.

  • Die Nutzlast : Die Nutzlast enthält normalerweise die Ansprüche, kann aber jede Art von Informationen kodieren. Ansprüche enthalten grob die Berechtigungen, die der Inhaber des Tokens hat: Zum Beispiel kann in einer typischen Web-App ein Token mit dem Anspruch read-post eine Liste aller Beiträge auf der Webplattform abrufen oder ein Benutzer, der über Der Anspruch delete-post kann einen Beitrag aus der App löschen. Wir werden die Ansprüche im Abschnitt Autorisierung ausführlicher behandeln.

  • Die Unterschrift : Die Signatur enthält die verschlüsselte Signatur, die die Gültigkeit des Tokens sicherstellt und dass der Inhalt während der Übertragung nicht verändert wurde.

Hier ist ein Beispiel für einen kleinen Token mit all seinen Teilen.

Node.js

Wie JSON-Webtoken eine Anwendung sichern

In diesem Tutorial werden wir der Kürze halber unser Token mit HS256 mit einem unsicheren Geheimnis kodieren, aber Sie können ein sicheres Geheimnis verwenden, damit Brute Forcen Ihrer mit HS256 kodierten Token nicht möglich ist.

reagieren nativen Fingerabdruckscanner

Das jwt |_+_| Funktion hat die folgende Signatur: |_+_|.

Im letzten Beispiel haben wir den JSON |_+_| mit dem unsicheren Geheimnis |_+_| verschlüsselt.

JWT-Fluss

In einer realen Anwendung sieht der JWT-Flow wie folgt aus:

  1. Der Client fordert einen Token vom Server an, entweder durch Angabe eines Passworts oder einer anderen Form der Authentifizierung (Fingerabdruck, Gesichts-ID usw.).
  2. Der Server stellt ein Token bereit. Obwohl es zwei Möglichkeiten gibt, das Token zu generieren, kann ein Angreifer in keiner Weise seine eigenen Token generieren, da er den öffentlichen und den privaten Schlüssel zum Generieren und Entschlüsseln des Tokens benötigt.
  • Wenn dieses Token mit einer sicheren Codierung wie HS256 generiert wird, wird das Token mit einem sicher gespeicherten Geheimnis generiert und auch gegen dieses Geheimnis geprüft
  • Bei Verwendung einer Verschlüsselung mit öffentlichem Schlüssel wie RSA wird der Token mit dem privaten Zertifikat generiert und der öffentliche Schlüssel erneut überprüft

Nachdem wir nun erklärt haben, was Token sind und wie sie gesichert werden, werden wir weiterhin erklären, wie sie im Kontext einer Webanwendung verwendet werden.

JWTs sind beliebt, weil sie in sich geschlossen sind und clientseitig gespeichert werden – das bedeutet, dass die Daten der Sitzung nicht serverseitig gespeichert werden müssen, wie dies z. klebrige Sitzungen

Traditioneller Middleware-Ansatz für die Authentifizierung

Bei der Arbeit mit Webdiensten ist Middleware der Industriestandard für die Implementierung der Authentifizierung. Eine Middleware ist einfach eine Funktion, die vom Server zu einem bestimmten Zeitpunkt im Lebenszyklus der Anforderung ausgeführt wird. Dies bedeutet, dass eine Middleware für einige Ressourcen ausgeführt werden kann und für andere nicht. Dies ist im Zusammenhang mit der Authentifizierung nützlich, da Sie möglicherweise einige Ressourcen schützen und andere öffentlich zugänglich machen möchten.

Eine Middleware hat neben der Authentifizierung noch andere Anwendungen, darunter unter anderem Protokollierung oder Fehlerbehandlung.

Im folgenden Beispiel sehen wir eine einfache Middleware mit |_+_|. Diese Middleware protokolliert nur eine Nachricht.

2 Werte Javascript zurückgeben
graphql-yoga

Die Schlüsselmethode in der Middleware ist die |_+_| Methode. Diese Methode signalisiert |_+_| um mit dem Anforderungslebenszyklus fortzufahren.

Verwenden von Middleware- und JWT-Funktionalität zusammen mit |_+_|

Jetzt müssen wir diese Middleware-Funktionalität irgendwie mit der JWT-Funktionalität kombinieren. Um dies zu erreichen, verwenden wir eine Funktion aus der JSON-Webtoken-Bibliothek namens |_+_|.

Die |_+_| Funktion hat folgende Signatur:

import * as jwt from 'jsonwebtoken' const token = jwt.sign({ claims: 'read-post' }, 'secret', { algorithm: 'HS256', }) console.log(token) // header - eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. // payload - eyJkYXRhIjoiZm9vYmFyIiwiaWF0IjoxNTQ0NjQ0ODI0fQ. // signature - IzNv-vRptcbU0S_qfqqKusEnwLzdUT_IsYjIcQl4KHk

Es braucht ein verschlüsseltes Token und ein Geheimnis. Wenn das Token gültig ist, d. h. der Inhalt wurde nicht manipuliert, gibt die Funktion das unverschlüsselte Token für den zweiten Parameter des Callbacks zurück; Wenn das Token ungültig ist, gibt die Funktion einen Fehler im ersten Parameter an den Callback zurück.

sign

Wie der Name schon sagt, |_+_| nimmt ein Token und prüft seine Gültigkeit anhand des geheimen Schlüssels, wobei das decodierte Token oder ein Fehler zurückgegeben wird.

In diesem Beispiel sehen wir, wie wir |_+_| . verwenden würden Funktion in Verbindung mit einer Middleware, um alle nach dieser Middleware deklarierten Ressourcen zu schützen.

Authentifizierung mit GraphQL mit |_+_|

|_+_| ist eine benutzerfreundliche GraphQL-Serverbibliothek, die wir für den Rest des Artikels wegen ihrer einfachen Einrichtung und der unkomplizierten Entwicklererfahrung verwenden werden.

Die Authentifizierung eines |_+_| server erweitert das besprochene Middleware-Paradigma und seit |_+_| basiert auf |_+_| und |_+_| aus |_+_| aufgebaut ist, können wir sogar genau dieselbe Middleware verwenden.

jwt.sign(payload, secretOrPrivateKey, [options, callback])

Diese Art der Authentifizierung funktioniert, funktioniert jedoch nicht gut mit GraphQL-Clients, da sie auf HTTP-Codes basiert. Eine bessere Möglichkeit wäre die Verwendung von GraphQLMiddlewares von |_+_|: Sie ermöglichen uns die Verwaltung der zusätzlichen Funktionen, die für alle unsere Resolver relevant sind.

Wir könnten auch |_+_| . verwenden von apollo-server-core, um eine Nachricht zu drucken, die von unserem GraphQL-Client Ihrer Wahl verarbeitet werden kann.

{ claims: 'read-post' }

Mit diesem Refactor wäre der GraphQL-Client, der sich in diesem Fall mit |_+_| verbindet, in der Lage, einen Authentifizierungsfehler auf anmutige Weise zu behandeln.

Genehmigung

Wir haben uns ein wenig damit beschäftigt, was Autorisierung ist. Wir können uns die Authentifizierung als den ersten Teil der Sicherheit unserer Anwendungen vorstellen, aber sobald jemand Zugriff auf unser System erhält, ist dies erst der Anfang der Geschichte.

Wie im vorherigen Abschnitt werden wir uns ansehen, wie Sie die Autorisierung in einer herkömmlichen REST-API implementieren, und kehren dann zu GraphQL zurück. Dazu müssen wir zunächst das Konzept der Behauptungen .

Im Kern stellen Ansprüche die Aktionen dar, die ein Benutzer innerhalb des Systems ausführen darf. Die beste Vorgehensweise besteht darin, Verben und Ressourcen zu verwenden. Ein Verb in einem Anspruch ist die Art von Aktion, die ein Benutzer für eine Ressource ausführen kann. Solche Verben können CRUD-Operationen (create, read, update, delete) sein. Ressourcen hingegen können alles von anderen Benutzern, Beiträgen oder Bildern sein.

Was ist Sparkpoint-Krypto?

Einige Beispiele für Ansprüche könnten sein: Beiträge löschen, mit denen ein Benutzer jeden Beitrag löschen kann, oder Bilder aktualisieren, mit denen jemand bereits erstellte Bilder aktualisieren kann.

Die Arbeit mit Ansprüchen in einer herkömmlichen REST-API besteht darin, zu Beginn jeder Anfrage nach den entsprechenden Ansprüchen zu suchen. Wenn die erforderlichen Ansprüche nicht vorhanden sind, wird die Anfrage nicht fortgesetzt, wie Sie in diesem Beispiel sehen können.

secret

Lassen Sie uns dieses Konzept nun mit GraphQL untersuchen.

Express.js

Das Problem bei diesem Ansatz besteht darin, dass wir daran denken müssen, jeden unserer Resolver mit Ansprüchen zu schützen. Bei einer kleinen Anzahl von Schadensfällen ist dieser Ansatz kein Problem, aber wenn wir Schadenskombinationen eingehen, gerät er schnell aus dem Ruder.

Verwenden von GraphQL Shield

Eine bessere Möglichkeit, die Anspruchsfunktionalität zu implementieren, ist mit import * as express from 'express' const app = express() app.get('/posts', (req, res) => { res.send('posts') }) app.use((req, res, next) => { console.log('message') }) app.get('/protected-posts', (req, res) => { res.send('protected posts') }) app.listen(3000, () => { console.log('listening on port 3000') }) , ein Tool, mit dem Sie eine Berechtigungsebene in einer Webanwendung erstellen können.

Mit |_+_| wir müssen für jeden Resolver in unserem Schema einen Regelsatz und das dekodierte Token für jede Regel bereitstellen. Diese Regel kann entscheiden, ob der Benutzer autorisiert ist oder nicht.

GraphQL Shield übersetzt das Konzept der Ansprüche in Regeln. Eine Regel in |_+_| schützt einen Teil des GraphQL-Schemas.

Wie im folgenden Beispiel zu sehen ist, müssen Sie zunächst die entsprechende Regel übergeben, um auf einen beliebigen Teil des GraphQL-Schemas zuzugreifen.

next()

Abschluss

Wir haben gelernt, wie wir durch die Verwendung von Web-Token und -Ansprüchen unsere GraphQL-API für mehrere Benutzer mit unterschiedlichen Berechtigungen besser schützen können, aber Authentifizierung und Autorisierung sind nur ein Teil des Sicherheitspuzzles. Um Ihre APIs und die Server, die sie hosten, weiter zu schützen, lesen Sie dies hier Wiki aus dem Open Web Application Security Project.

#graphql #jwt #json #javascript #webdev