it-swarm-eu.dev

Sichern einer JavaScript Single Page App mit RESTful Backend

Ich bin gerade dabei, ein JavaScript-SPA zu erstellen, und habe nachgeforscht, wie ich es sichern kann. Derzeit gibt es eine RESTful-API, mit der über AJAX vollständig interagiert wird. Wir haben auch mobile Clients, die mit dieser API interagieren. Derzeit wird nur die HTTP-BASIC-Authentifizierung über SSL unterstützt. Die JavaScript-App kommuniziert auch ausschließlich über SSL, BASIC Auth schneidet sie jedoch nicht ab, da das Kennwort (oder eine Ableitung davon) auf dem Client gespeichert werden muss. Schließlich wird die SPA-App aus reinem JavaScript und HTML bestehen und auf demselben Server wie die RESTful-API bereitgestellt, jedoch ohne serverseitiges Framework.

Ziele :

  • Kein serverseitiges Framework für den Javascript-Client (es ist nur ein anderer Client).
  • Behalten Sie die Statuslosigkeit der RESTful-API aus den typischen Gründen (Skalierbarkeit, Fehlertoleranz, vereinfachte Bereitstellung usw.) bei.
  • Jeder Status sollte vom Client verwaltet werden. Für die Zwecke dieser Frage bedeutet dies die Anmeldeinformationen.
  • Der vom Client verwaltete Anmeldestatus muss sicher und resistent gegen Sitzungsentführungen und ähnliche Angriffe sein.

Was ich mir ausgedacht habe, basiert auf meiner Forschung zu OAuth und ähnlichen Schemata (Amazon usw.).

  1. Der Benutzer meldet sich mit und HTTP POST über SSL) an.
  2. Der Server berechnet einen Hash wie folgt:

    HMAC (Schlüssel, Benutzer-ID + ":" + IP-Adresse + ":" + Benutzer-Agent + ":" + todaysDateInMilliseconds)

  3. Dieses Token wird an den Client zurückgegeben und bei jeder nachfolgenden Anforderung anstelle des Benutzernamens und des Kennworts bereitgestellt. Es wird höchstwahrscheinlich in localStorage oder einem Cookie gespeichert.

Ist das sicher? Meine Motivation für die Auswahl der Benutzer-ID, ipAddress, todaysDateInMilleseconds besteht darin, ein Token zu erstellen, das nur für heute gültig ist, jedoch nicht für jede Anforderung eine Datenbanksuche erfordert UND sicher auf dem Client gespeichert werden kann. Ich kann nicht darauf vertrauen, dass der Schlüssel nicht komprimiert wird, daher die Einbeziehung der IP-Adresse in einen Versuch, Sitzungsentführungen zu verhindern.

Lassen Sie mich den folgenden Link aus einem verwandten Beitrag auf StackExchange einfügen, da er meiner Meinung nach viele der Probleme behebt, die ich zu lösen versuche: REST- und zustandslose Sitzungs-IDs

Nach dem ersten Feedback hier habe ich beschlossen, nur die ersten beiden Oktects der IP-Adresse zu verwenden, um Clients hinter Proxys und mobilen Clients besser zu behandeln. Es ist immer noch nicht perfekt, aber es ist ein Kompromiss für zusätzliche Sicherheit.

68
Jon Wingfield

Der vom Token angebotene Dienst besteht darin, dass der Server das Token irgendwie als eines seiner eigenen erkennt. Wie kann der Server ein HMAC-basiertes Token validieren? Durch Neuberechnung mit seinem geheimen HAMC-Schlüssel und den Daten, über die HMAC arbeitet . Wenn Sie möchten, dass Ihr Token über die Benutzer-ID, das Kennwort, die IP-Adresse und das Datum berechnet wird, muss der Server alle diese Informationen kennen. Sie möchten jedoch nicht, dass Ihr Server das Kennwort speichert, und der Client sendet es nicht bei jeder Anforderung zurück. Wie kann Ihr System dann funktionieren?

Die Grundidee ist jedoch gesund:

  • Benutzer "melden sich an" auf eine Weise, die Sie für richtig halten.
  • Bei einer solchen Anmeldung sendet der Server einen Cookie-Wert, der bei jeder nachfolgenden Anforderung zurückgesendet wird (genau das tun Cookies).
  • Das Cookie enthält die Benutzer-ID, das Ausstellungsdatum und einen Wert m = HMAC (K, Benutzer-ID || Datum || IP) .
  • Wenn der Server eine Anforderung empfängt, überprüft er das Cookie: Die Benutzer-ID und das Datum stammen aus dem Cookie selbst, die Quell-IP wird von der Webserverschicht abgerufen und der Server kann den Wert m neu berechnen , um zu überprüfen, ob es mit dem im Cookie gespeicherten übereinstimmt.

Sie können das gesamte Cookie durch eine zufällige Sitzungs-ID ersetzen, wenn der Server über (temporären) Speicherplatz verfügt. In der Tat könnte sich der Server an die Zuordnung von einer zufälligen Sitzungs-ID zu benutzerspezifischen Informationen (wie seinem Namen und seiner IP-Adresse) erinnern; Die alte Sitzungs-ID kann automatisch abgelaufen werden, sodass der Speicherplatz nicht unbegrenzt wächst. Das oben beschriebene Cookie ist nur eine Möglichkeit, Speicher auszulagern auf dem Client selbst.

Hinweis : Die Verwendung der IP-Adresse kann einige praktische Probleme mit sich bringen. Einige Clients stehen hinter Proxys, sogar Proxys mit Lastenausgleich. Daher ist nicht nur die Client-IP-Adresse möglicherweise "verborgen" (auf dem Server sehen Sie die Adresse des Proxys, nicht die Adresse des Clients), sondern auch die IP-Adresse, die Sie serverseitig erhalten Bewegen Sie sich unregelmäßig (wenn zwei aufeinanderfolgende Anforderungen des Clients unterschiedliche Proxys in einer Proxy-Farm durchlaufen haben).

30
Thomas Pornin

Es gibt eine viel einfachere Lösung:

Verwenden Sie SSL-Sitewide und dann die Standard-Sitzungsverfolgung Ihres Frameworks.

Das ist alles was Sie tun müssen.

Im Einzelnen meldet sich der Benutzer zunächst mit seinem Benutzernamen und seinem Kennwort an. Es wird an den Server gesendet, der seine Gültigkeit überprüfen kann. Wenn die Authentifizierung erfolgreich ist, setzt Ihr Servercode im Sitzungsstatus ein Flag, das daran erinnert, dass sich der Benutzer erfolgreich authentifiziert hat, und an den Benutzernamen des Benutzers. Alle nachfolgenden Anforderungen befinden sich in derselben Sitzung, sodass Sie sie problemlos authentifizieren und fortfahren können.

(Noch detaillierter: Jedes Mal, wenn Sie eine Anfrage erhalten, überprüfen Sie den Sitzungsstatus, um festzustellen, ob der Benutzer sich erfolgreich authentifiziert hat und zur Ausführung dieser Aktion berechtigt ist. Wenn ja, lassen Sie die Anfrage zu und führen die Aktion aus. Wenn nein, leiten Sie um den Benutzer auf eine Anmeldeseite oder eine andere Fehlermeldung anzeigen.)

Beachten Sie, dass dies alle Ihre Anforderungen erfüllt. Es ist nicht für jede Anforderung eine Datenbanksuche erforderlich. Es ist mit einer RESTful-API kompatibel. Es ist mit einer einseitigen App kompatibel. Sie müssen nichts Besonderes codieren: Sie verwenden nur die vorhandene Unterstützung Ihres Frameworks für Sitzungen (normalerweise wird ein Sitzungscookie mit einer eindeutigen Sitzungs-ID und ein Mechanismus zum Speichern des Status auf der Serverseite verwendet, der dieser Sitzungs-ID zugeordnet ist). .

Im Rahmen der Verwendung von SSL auf der gesamten Website sollten Sie das sichere Flag in Ihrem Sitzungs-ID-Cookie setzen, um es vor Abhören zu schützen (dies stellt sicher, dass es niemals über HTTP gesendet wird). Sie sollten auch HSTS aktivieren, um den Browser anzuweisen, auf Ihrer Site immer SSL zu verwenden. Durchsuchen Sie diese Website nach weiteren Informationen zum Bereitstellen von SSL-Sitewide.

Sie sollten sich nicht darauf verlassen, dass die IP-Adresse des Clients statisch ist. Sie kann sich beispielsweise ändern, wenn der Client mobil ist und von einem drahtlosen Netzwerk zu einem anderen wechselt. Vermeiden Sie daher am besten, die IP-Adresse des Clients für irgendetwas zu verwenden.

9
D.W.

Überprüfen Sie diesen Beitrag Verwenden von OAuth2 in HTML5 Web App . Die Antwort von @jandersen bietet eine gute Erklärung für die Verwendung von Anmeldeinformationen für das Kennwort des Ressourcenbesitzers flow in Anwendungen mit nur einer Seite. In jedem Fall sollte der bevorzugte Ablauf für diese Apps implizite Gewährung sein. In der Antwort von @jandersen auf den Beitrag, auf den verwiesen wird, geht es darum, die Kennwortanmeldeinformationen des Ressourcenbesitzers so zu ändern, dass sie dem impliziten Zuschuss nahe kommen.

3
Daniel Cerecedo