Token-basierte Authentifizierung mithilfe von Zugriffs- und Aktualisierungstoken

8

Ich implementiere ein tokenbasiertes Authentifizierungssystem für eine REST-API unter Verwendung eines kurzlebigen Zugriffstokens und eines langlebigen Aktualisierungstokens. Dies ist eine abstrakte Übersicht über die relevanten API-Endpunkte (HTTPS wird für alle Endpunkte erzwungen):

Endpunkte:

POST /register/
POST /login/
POST /logout/
POST /password/change/

Implementierung:

POST /register/::

  • Anfrage: Der Client sendet Benutzernamen, E-Mail und Passwort in JSON.
  • Serveraktionen:
    1. Überprüft die Eingabe, erstellt einen Benutzer in der Datenbank (speichert Benutzer-ID, Benutzername, E-Mail und Kennwort-Hash).
    2. Erstellt ein kurzlebiges Zugriffstoken im JWT-Format (enthält Benutzer-ID, Ausstellungsdatum und Ablaufdatum).
    3. Erstellt ein langlebiges Aktualisierungstoken als UUID-Zeichenfolge und speichert es in der Datenbank (speichert die Benutzer-ID und das Aktualisierungstoken).
  • Antwort: Der Server gibt das Zugriffstoken und das Aktualisierungstoken in JSON zurück.

POST /login/::

  • Anfrage: Client sendet Benutzername und Passwort in JSON.
  • Serveraktionen:
    1. Überprüft die Eingabe und prüft, ob die Anmeldeinformationen gültig sind, indem die Datenbank überprüft wird.
    2. Wenn Anmeldeinformationen gültig sind, werden wie zuvor erwähnt kurzlebige Zugriffstoken und langlebige Aktualisierungstoken erstellt.
  • Antwort: Entspricht dem /register/Zugriffstoken und dem Aktualisierungstoken in JSON.

POST /logout/::

  • Anforderung: Der Client sendet ein Aktualisierungstoken im AuthorizationHeader als BearerToken.
  • Serveraktionen:
    1. Überprüft das Aktualisierungstoken durch Überprüfen der Aktualisierungstoken-Datenbank.
    2. Entfernt das Aktualisierungstoken aus der Datenbank.
      Hinweis: Dadurch bleibt das Zugriffstoken gültig, aber da es nur von kurzer Dauer ist (ca. 1 Stunde, denke ich, sollte es in Ordnung sein).
  • Antwort: Gibt zurück, ob die Abmeldeanforderung in JSON erfolgreich verarbeitet wurde.

POST /password/change/::

  • Anforderung: Der Client sendet das Zugriffstoken im AuthorizationHeader als BearerToken und sendet außerdem das alte und das neue Kennwort in JSON über HTTPS.
  • Serveraktionen:
    1. Dekodiert das Zugriffstoken, um den Benutzer abzurufen, und überprüft das alte Kennwort des Benutzers mit der Datenbank.
    2. Setzt den Kennwort-Hash des Benutzers in der Datenbank auf den Hash des neuen Kennworts.
    3. Entfernt alle Aktualisierungstoken, die dem Benutzer in der Aktualisierungstoken-Datenbank zugeordnet sind, um vorhandene Sitzungen im Wesentlichen abzumelden (kurzlebige Zugriffstoken bleiben gültig).
  • Antwort: Gibt zurück, ob die Kennwortänderungsanforderung in JSON erfolgreich verarbeitet wurde.

Fragen:

  1. Ist dieser Ansatz sicher? Speziell:
    • Ist das Senden des Benutzernamens und des Kennworts über JSON sicher, wenn dies über HTTPS erfolgt? Wie kann ich verhindern, dass nicht autorisierte Domänen diesen Endpunkt anrufen? Wie würde ich außerdem programmatische Anmeldungen verhindern?
    • Sollten die Aktualisierungstoken gehasht werden, bevor sie in der Datenbank gespeichert werden, oder bin ich nur paranoid?
  2. Wenn der Client ein Webbrowser wäre, wie würde ich das Aktualisierungstoken sicher auf dem Client speichern?
    • Eine Idee zum Speichern des Aktualisierungstokens ist: Wenn sich der Benutzer anmeldet, speichert der Server das Token zusätzlich zum Senden des Aktualisierungstokens an den Client in einem HttpOnlyCookie mit einem secureFlag. Die Autorisierung erfolgt weiterhin über den AuthorizationHeader. Wenn der Client jedoch zum ersten Mal geladen wird, kann er eine GETAnforderung an einen Endpunkt senden , der prüft, ob das Cookie ein gültiges Aktualisierungstoken enthält, und es in diesem Fall an den Benutzer in JSON zurückgeben. Mit anderen Worten, das einzige Mal, dass das Cookie tatsächlich verwendet wird, besteht darin, das Aktualisierungstoken im Cookie an den Client zurückzugeben. Ist dieser Ansatz sicher? Ich denke, es wird CSRF verhindern, da es keine Nebenwirkungen gibt, wenn das Aktualisierungstoken vom Cookie angefordert wird. Aber gibt es eine andere Möglichkeit, wie ein Angreifer das Aktualisierungstoken abfangen könnte (unter der Annahme von HTTPS)?
Kootling
quelle
2
Warum nicht Open ID Connect verwenden, anstatt zu versuchen, Ihren eigenen Anmeldesicherheitsmechanismus zu implementieren?
Erik Eidt
Ich möchte keinen zusätzlichen Server verwalten müssen, um als OpenID-Verbindungsanbieter zu fungieren. Außerdem hätte ich lieber die volle Kontrolle über den Authentifizierungsfluss, damit ich Fehler und Sicherheitslücken leicht lokalisieren kann.
Kootling
2
Ich denke nicht, dass dies einen zusätzlichen Server erfordert, wenn Sie ihn nur verwenden. Die eigene Implementierung mit Ihrem eigenen Protokoll birgt möglicherweise mehr Sicherheitsrisiken als die Verwendung des neuen Standardansatzes. Aber wer weiß das schon?
Erik Eidt

Antworten:

2

Ist dieser Ansatz sicher? Speziell:

  • Ist das Senden des Benutzernamens und des Kennworts über JSON sicher, wenn dies über HTTPS erfolgt?

Ja. Header, Anforderungsparameter und Anforderungshauptteil werden während der Kommunikation verschlüsselt.

Sobald Sie sich auf der Serverseite befinden, protokollieren Sie den Anfragetext nicht :-)

  • Wie kann ich verhindern, dass nicht autorisierte Domänen diesen Endpunkt anrufen?

Du kannst nicht. Sobald sich die API im WWW befindet, ist sie automatisch jeder Art von Bosheit ausgesetzt. Das Beste, was Sie tun können, ist, vorbereitet zu sein und sich der Bedrohungen bewusst zu sein. Zumindest über diejenigen, die dich betreffen. Schauen Sie hier .

Ein möglicher Ansatz für das Problem könnte darin bestehen, einen API-Manager zu implementieren (oder zu beauftragen) .

On-Premise-API-Manager können die Angriffsfläche reduzieren, da nicht alle Endpunkte hinter dem AM unbedingt öffentlich sind.

Sie könnten mit einigen Produkten in der Cloud das gleiche Ergebnis erzielen, aber sie sind für den Mainstream absurd teuer.

Auf jeden Fall bleiben die API-Verwaltungsendpunkte Angriffen ausgesetzt.

  • Wie würde ich außerdem programmatische Anmeldungen verhindern?

Wenn Sie mit programmatischen Anmeldungen Angriffe mit brutaler Gewalt meinen, sollten ein Schwellenwert (maximale Anzahl zulässiger Anforderungen pro Sekunde) und eine schwarze Liste ausreichen, um das Bestehen des Angreifers zu verhindern. Weitere Informationen finden Sie hier .

Viele der API-Manager bieten sofort einsatzbereite API-Ratenlimitkonfigurationen und Whitelists .

Wenn Sie mit der Google API-Konsole vertraut sind, können Sie erraten, was ein API-Manager tun kann.

  • Sollten die Aktualisierungstoken gehasht werden, bevor sie in der Datenbank gespeichert werden, oder bin ich nur paranoid?

Unabhängig davon, ob es sich bei dem Aktualisierungstoken um eine einfache UUID oder um etwas anderes handelt, möchte ich diese Art von Implementierungsdetails nicht offenlegen. Also würde ich vorschlagen, es zu hashen. Je undurchsichtiger die Implementierungsdetails der Sicherheitsschicht sind, desto besser.

Informationen zur JWT-Sicherheit finden Sie hier .

  • Wenn der Client ein Webbrowser wäre, wie würde ich das Aktualisierungstoken sicher auf dem Client speichern?

Möglicherweise interessieren Sie sich für JSON Web Token (JWT) - Speicher auf der Clientseite .

Laiv
quelle
In Bezug auf programmatische Anmeldungen möchte ich verhindern, dass jemand sein eigenes Front-End für die API erstellt (obwohl dies, wie Sie sagten, praktisch unmöglich ist). Außerdem werden die Aktualisierungstoken (die UUIDs und keine JWTs sind) derzeit als Klartext in der Datenbank gespeichert, daher sollte ich sie auf jeden Fall hashen, oder? In Bezug auf den clientseitigen Token-Speicher möchte ich die Aktualisierungstoken speichern und über Sitzungen hinweg beibehalten, damit sessionStoragesie nicht funktionieren. Auch localStorageund document.cookiescheinen unsicher, da sie über JavaScript zugegriffen werden können. Ist mein Ansatz sinnvoll oder möglicherweise unsicher?
Kootling
1. Ja, ich würde ein Hash-Token anstelle des Klartextes speichern. Nur um den Inhalt der Tabelle für andere Prozesse undurchsichtig zu machen. 2. Wenn ich zwischen localStorage und Cookies wählen muss, wähle ich Cookies. Trotzdem würde ich zunächst ein wenig über seine Schwachstellen recherchieren. Erwägen Sie außerdem, der Sicherheit einen Mechanismus hinzuzufügen, mit dem Token manuell ungültig gemacht werden können.
Laiv
Mit "Cookies" meinen Sie document.cookieein HttpOnly-Cookie mit einer sicheren Flagge, ähnlich dem oben erwähnten Ansatz?
Kootling
HttpOnly und Secure Flag hindern Sie nicht an XST und XSRF. Aber es macht das Cookie sicher für XSS-Angriffe, die ich für grundlegend halte. Also ja, HttpOnly und sichere Flagge.
Denken
Wie auch immer, ich empfehle Ihnen, die verschiedenen OWASP-Projekte in Bezug auf Webanwendungen, API, REST und JWT zu überprüfen. Sie finden weit mehr Informationen als die, die ich Ihnen hier zur Verfügung stellen kann.
Laiv