it-swarm.com.de

SPA-Best Practices für Authentifizierung und Sitzungsverwaltung

Wenn Sie Anwendungen im SPA-Stil mit Frameworks wie Angular, Ember, React usw. erstellen, welche Best Practices für die Authentifizierung und Sitzungsverwaltung halten die Benutzer für empfehlenswert? Ich kann mir verschiedene Möglichkeiten vorstellen, um das Problem anzugehen.

  1. Behandeln Sie es nicht anders als die Authentifizierung mit einer normalen Webanwendung, vorausgesetzt, API und Benutzeroberfläche haben dieselbe Origin-Domäne.

    Dies würde wahrscheinlich ein Sitzungscookie, einen serverseitigen Sitzungsspeicher und möglicherweise einen Sitzungs-API-Endpunkt beinhalten, auf den die authentifizierte Web-Benutzeroberfläche zugreifen kann, um aktuelle Benutzerinformationen abzurufen, die bei der Personalisierung helfen oder möglicherweise sogar die Rollen/Fähigkeiten auf der Clientseite bestimmen. Der Server würde natürlich weiterhin Regeln zum Schutz des Zugriffs auf Daten durchsetzen. Die Benutzeroberfläche würde diese Informationen nur verwenden, um die Benutzererfahrung anzupassen.

  2. Behandeln Sie es wie einen Drittanbieter-Client, der eine öffentliche API verwendet, und authentifizieren Sie sich mit einem ähnlichen Tokensystem wie OAuth. Dieser Token-Mechanismus wird von der Client-Benutzeroberfläche verwendet, um jede einzelne Anforderung an die Server-API zu authentifizieren.

Ich bin hier kein wirklicher Experte, aber # 1 scheint für die überwiegende Mehrheit der Fälle völlig ausreichend zu sein, aber ich würde gerne mehr erfahrene Meinungen hören.

275
Chris Nicola

Diese Frage wurde in einer etwas anderen Form ausführlich hier angesprochen:

RESTful Authentication

Damit wird es aber von der Serverseite aus angesprochen. Schauen wir uns dies vom Client aus an. Bevor wir das tun, gibt es jedoch ein wichtiges Vorspiel:

Javascript-Krypto ist hoffnungslos

Matasanos Artikel darüber ist berühmt, aber die darin enthaltenen Lektionen sind ziemlich wichtig:

http://www.matasano.com/articles/javascript-cryptography/

Zusammenfassen:

  • Ein Man-in-the-Middle-Angriff kann Ihren Krypto-Code trivial durch <script> function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script> ersetzen.
  • Ein Man-in-the-Middle-Angriff ist für eine Seite, die Ressourcen über eine Nicht-SSL-Verbindung bereitstellt, trivial.
  • Sobald Sie SSL haben, verwenden Sie sowieso echte Krypto.

Und um eine Folge meiner eigenen hinzuzufügen:

  • Ein erfolgreicher XSS-Angriff kann dazu führen, dass ein Angreifer Code auf dem Browser Ihres Clients ausführt, auch wenn Sie SSL verwenden. Selbst wenn Sie jede Lücke geschlossen haben, kann Ihre Browserkrypto dennoch fehlschlagen, wenn Ihr Angreifer eine Möglichkeit zur Ausführung findet Beliebiger Javascript-Code im Browser eines anderen Benutzers.

Dies macht viele RESTful-Authentifizierungsschemata unmöglich oder albern, wenn Sie beabsichtigen, einen JavaScript-Client zu verwenden. Sehen wir mal!

HTTP Basic Auth

In erster Linie HTTP Basic Auth. Das einfachste Schema: Geben Sie bei jeder Anfrage einfach einen Namen und ein Passwort ein.

Dies setzt natürlich unbedingt SSL voraus, da Sie bei jeder Anfrage einen Base64 (reversibel) verschlüsselten Namen und ein Passwort übergeben. Jeder, der in der Leitung zuhört, kann Benutzernamen und Passwort trivial extrahieren. Die meisten Argumente für "Grundlegende Authentifizierung ist unsicher" stammen von einer Stelle mit "Grundlegender Authentifizierung über HTTP", was eine schreckliche Idee ist.

Der Browser bietet eingebaute HTTP Basic Auth-Unterstützung, aber es ist hässlich wie Sünde und Sie sollten es wahrscheinlich nicht für Ihre App verwenden. Die Alternative besteht jedoch darin, Benutzernamen und Passwort in JavaScript zu verstecken.

Dies ist die RESTVOLLSTE Lösung. Der Server benötigt keinerlei Kenntnis über den Status und authentifiziert jede einzelne Interaktion mit dem Benutzer. Einige REST) Enthusiasten (meistens Strohmänner) bestehen darauf, dass die Aufrechterhaltung irgendeines Zustands eine Häresie ist und im Mund aufschäumen wird, wenn Sie an eine andere Authentifizierungsmethode denken. Compliance - wird von Apache standardmäßig unterstützt - Sie können Ihre Objekte als Dateien in Ordnern speichern, die durch .htaccess-Dateien geschützt sind, wenn Sie dies wünschen!

Das Problem ? Sie zwischenspeichern clientseitig einen Benutzernamen und ein Passwort. Dies gibt evil.ru ein besseres Gefühl - selbst die grundlegendsten XSS-Sicherheitslücken können dazu führen, dass der Client seinen Benutzernamen und sein Passwort an einen bösen Server sendet. Sie könnten versuchen, dieses Risiko durch Hashing und Salting des Kennworts zu verringern. Beachten Sie jedoch Folgendes: JavaScript-Krypto ist hoffnungslos . Sie könnten dieses Risiko mindern, indem Sie es der Basisauthentifizierungsunterstützung des Browsers überlassen.

HTTP Digest Auth

Ist Digest-Authentifizierung mit jQuery möglich?

Eine "sicherere" Authentifizierung, dies ist eine Anfrage/Antwort-Hash-Herausforderung. Außer , dass JavaScript Crypto hoffnungslos ist , funktioniert es nur über SSL und Sie müssen den Benutzernamen und das Passwort auf der Clientseite zwischenspeichern, was es komplizierter macht als HTTP Basic Auth aber nicht mehr sicher.

Abfrageauthentifizierung mit zusätzlichen Signaturparametern.

Eine weitere "sicherere" Authentifizierung, bei der Sie Ihre Parameter mit Nonce- und Timing-Daten verschlüsseln (zum Schutz vor Wiederholungs- und Timing-Angriffen) und die E-Mails senden. Eines der besten Beispiele dafür ist das OAuth 1.0-Protokoll, das meines Wissens eine ziemlich umwerfende Methode ist, um die Authentifizierung auf einem REST zu implementieren Server.

http://tools.ietf.org/html/rfc5849

Oh, aber es gibt keine OAuth 1.0-Clients für JavaScript. Warum?

JavaScript Crypto ist hoffnungslos , denken Sie daran. JavaScript kann nicht an OAuth 1.0 ohne SSL teilnehmen, und Sie müssen den Benutzernamen und das Kennwort des Clients immer noch lokal speichern. Dies entspricht der Digest-Authentifizierung. Dies ist komplizierter als HTTP Basic Auth aber es ist nicht mehr sicher.

Zeichen

Der Benutzer sendet einen Benutzernamen und ein Kennwort und erhält im Gegenzug ein Token, mit dem Anforderungen authentifiziert werden können.

Dies ist geringfügig sicherer als HTTP Basic Auth, da Sie die vertraulichen Daten verwerfen können, sobald die Transaktion mit Benutzername/Kennwort abgeschlossen ist. Es ist auch weniger RESTful, da Token "state" darstellen und die Serverimplementierung komplizierter machen.

SSL noch

Das Problem ist jedoch, dass Sie immer noch den anfänglichen Benutzernamen und das Passwort senden müssen, um ein Token zu erhalten. Sensible Informationen berühren immer noch Ihr kompromittierbares JavaScript.

Um die Anmeldeinformationen Ihres Benutzers zu schützen, müssen Sie Angreifer weiterhin von JavaScript fernhalten und einen Benutzernamen und ein Kennwort über das Internet senden. SSL erforderlich.

Token-Ablauf

Es ist üblich, Token-Richtlinien wie "Hey, wenn dieses Token zu lange existiert, verwerfen Sie es und veranlassen Sie den Benutzer, sich erneut zu authentifizieren." Durchzusetzen. oder "Ich bin mir ziemlich sicher, dass die einzige IP-Adresse, die dieses Token verwenden darf, XXX.XXX.XXX.XXX ist." Viele dieser Richtlinien sind ziemlich gute Ideen.

Feuerschaf

Die Verwendung eines Tokens ohne SSL ist jedoch immer noch anfällig für einen Angriff namens "Sidejacking": http://codebutler.github.io/firesheep/

Der Angreifer erhält die Anmeldeinformationen Ihres Benutzers nicht, kann sich jedoch als Benutzer ausgeben, was ziemlich schlimm sein kann.

tl; dr: Das Senden unverschlüsselter Token über das Netzwerk bedeutet, dass Angreifer diese Token einfach abfangen und sich als Benutzer ausgeben können. FireSheep ist ein Programm, das dies sehr einfach macht.

Eine separate, sicherere Zone

Je größer die Anwendung ist, die Sie ausführen, desto schwieriger ist es, absolut sicherzustellen, dass sie keinen Code einfügen können, der die Art und Weise ändert, in der Sie vertrauliche Daten verarbeiten. Vertrauen Sie Ihrem CDN absolut? Ihre Inserenten? Ihre eigene Codebasis?

Gilt für Kreditkartendaten und weniger für Benutzernamen und Kennwort - einige Implementierer speichern die Eingabe vertraulicher Daten auf einer vom Rest ihrer Anwendung getrennten Seite. Diese Seite kann so genau wie möglich kontrolliert und gesperrt werden, vorzugsweise auf einer solchen Seite Es ist schwierig, Benutzer mit Phishing zu infizieren.

Cookie (bedeutet nur Token)

Es ist möglich (und üblich), das Authentifizierungstoken in einem Cookie abzulegen. Dies ändert nichts an den Eigenschaften von auth mit dem Token, es ist eher eine praktische Sache. Alle vorherigen Argumente gelten weiterhin.

Sitzung (bedeutet immer noch nur Token)

Die Sitzungsauthentifizierung ist nur eine Tokenauthentifizierung, mit ein paar Unterschieden, die den Eindruck einer etwas anderen Sache erwecken:

  • Benutzer beginnen mit einem nicht authentifizierten Token.
  • Das Backend verwaltet ein Statusobjekt, das an das Token eines Benutzers gebunden ist.
  • Das Token wird in einem Cookie bereitgestellt.
  • Die Anwendungsumgebung abstrahiert die Details von Ihnen.

Abgesehen davon unterscheidet es sich jedoch nicht wirklich von Token Auth.

Dies geht sogar noch weiter von einer REST-konformen Implementierung entfernt - mit Statusobjekten gehen Sie auf einem Stateful-Server den Pfad des einfachen alten RPC immer weiter zurück.

OAuth 2.0

OAuth 2.0 befasst sich mit dem Problem: "Wie gewährt Software A Software B Zugriff auf die Daten von Benutzer X, ohne dass Software B Zugriff auf die Anmeldeinformationen von Benutzer X hat."

Die Implementierung ist so ziemlich nur eine Standardmethode für einen Benutzer, um ein Token zu erhalten, und dann für einen Drittanbieter, um "Ja, dieser Benutzer und dieses Token stimmen überein, und Sie können jetzt einige ihrer Daten von uns erhalten."

Grundsätzlich ist OAuth 2.0 nur ein Token-Protokoll. Es weist dieselben Eigenschaften wie andere Token-Protokolle auf - Sie benötigen weiterhin SSL, um diese Token zu schützen - es ändert lediglich die Art und Weise, wie diese Token generiert werden.

Es gibt zwei Möglichkeiten, wie OAuth 2.0 Ihnen helfen kann:

  • Weitergabe von Authentifizierung/Informationen an andere
  • Authentifizierung/Informationen von anderen erhalten

Aber wenn es darauf ankommt, benutzt man nur ... Token.

Zurück zu deiner Frage

Die Frage, die Sie stellen, lautet also: "Sollte ich mein Token in einem Cookie speichern und die automatische Sitzungsverwaltung meiner Umgebung die Details berücksichtigen, oder sollte ich mein Token in Javascript speichern und diese Details selbst verarbeiten?"

Und die Antwort ist: mach was immer dich glücklich macht.

Die Sache bei der automatischen Sitzungsverwaltung ist jedoch, dass hinter den Kulissen viel Magie für Sie geschieht. Oft ist es besser, selbst die Kontrolle über diese Details zu haben.

Ich bin 21, also ist SSL ja

Die andere Antwort lautet: Verwenden Sie https für alles oder Briganten stehlen die Passwörter und Token Ihrer Benutzer.

435
Curtis Lassam

Sie können die Sicherheit beim Authentifizierungsprozess erhöhen, indem Sie JWT (JSON-Web-Tokens) und SSL/HTTPS verwenden.

Die Basisauthentifizierungs-/Sitzungs-ID kann gestohlen werden über:

  • MITM-Angriff (Man-In-The-Middle) - ohne SSL/HTTPS
  • Ein Eindringling, der Zugriff auf den Computer eines Benutzers erhält
  • XSS

Mit JWT verschlüsseln Sie die Authentifizierungsdetails des Benutzers und speichern diese auf dem Client. Sie senden sie zusammen mit jeder Anforderung an die API, wo der Server/die API das Token validiert. Es kann nicht ohne den privaten Schlüssel (den der Server/die API geheim speichert) entschlüsselt/gelesen werden  Update lesen .

Der neue (sicherere) Fluss wäre:

Einloggen

  • Benutzer meldet sich an und sendet Anmeldeinformationen an API (über SSL/HTTPS)
  • API erhält Anmeldeinformationen
  • Falls gültig:
    • Registrieren Sie eine neue Sitzung in der Datenbank Update lesen
    • Verschlüsseln Sie Benutzer-ID, Sitzungs-ID, IP-Adresse, Zeitstempel usw. in einem JWT mit einem privaten Schlüssel.
  • API sendet das JWT-Token zurück an den Client (über SSL/HTTPS)
  • Der Client empfängt das JWT-Token und speichert es in localStorage/cookie

Jede Anfrage an API

  • Der Benutzer sendet eine HTTP-Anforderung an API (über SSL/HTTPS) mit dem im HTTP-Header gespeicherten JWT-Token
  • Die API liest den HTTP-Header und entschlüsselt das JWT-Token mit seinem privaten Schlüssel
  • Die API überprüft das JWT-Token, gleicht die IP-Adresse aus der HTTP-Anforderung mit der im JWT-Token ab und prüft, ob die Sitzung abgelaufen ist
  • Falls gültig:
    • Antwort mit angefordertem Inhalt zurückgeben
  • Falls ungültig:
    • Ausnahme auslösen (403/401)
    • Markieren Sie das Eindringen in das System
    • Senden Sie eine Warn-E-Mail an den Benutzer.

Aktualisiert am 30.07.15:

JWT-Nutzdaten/-Ansprüche können tatsächlich ohne den privaten Schlüssel (geheim) gelesen werden und es ist nicht sicher, sie in localStorage zu speichern. Es tut mir leid wegen dieser falschen Aussagen. Sie scheinen jedoch an einem JWE-Standard (JSON Web Encryption) zu arbeiten.

Ich implementierte dies, indem ich Ansprüche (userID, exp) in einem JWT speicherte, sie mit einem privaten Schlüssel (secret) signierte, den die API/das Backend nur kennt, und sie als sicheres HttpOnly-Cookie auf dem Client speicherte. Auf diese Weise kann es nicht über XSS gelesen und manipuliert werden, da sonst die Signaturüberprüfung des JWT fehlschlägt. Durch die Verwendung eines secure HttpOnly Cookies stellen Sie sicher, dass das Cookie nur über HTTP-Anforderungen (nicht für Skripte zugänglich) und nur über eine sichere Verbindung (HTTPS) gesendet wird.

Aktualisiert am 17.07.16:

JWTs sind von Natur aus staatenlos. Das bedeutet, dass sie sich selbst ungültig machen/verfallen. Indem Sie die SessionID zu den Ansprüchen des Tokens hinzufügen, machen Sie diesen statusabhängig, da seine Gültigkeit nicht nur von der Signaturüberprüfung und dem Ablaufdatum abhängt, sondern auch vom Sitzungsstatus auf dem Server. Der Vorteil ist jedoch, dass Sie Token/Sitzungen leicht ungültig machen können, was mit zustandslosen JWTs vorher nicht möglich war.

50
Gaui

Ich würde mich für das zweite entscheiden, das Tokensystem.

Wussten Sie schon über ember-auth oder ember-simple-auth ? Beide verwenden das tokenbasierte System, wie zum Beispiel die Glut-Simple-Auth-Zustände:

Eine schlanke und unauffällige Bibliothek zur Implementierung der tokenbasierten Authentifizierung in Ember.js-Anwendungen. http://ember-simple-auth.simplabs.com

Sie verfügen über eine Sitzungsverwaltung und lassen sich problemlos in vorhandene Projekte integrieren.

Es gibt auch eine Ember App Kit-Beispielversion von ember-simple-auth: Arbeitsbeispiel für das ember-app-kit, das ember-simple-auth für die OAuth2-Authentifizierung verwendet.

7
DelphiLynx