Les meilleures pratiques de SPA pour l'authentification et la gestion de session

lors de la construction D'applications de style SPA utilisant des cadres comme Angular, Ember, React, etc. selon les gens, quelles sont les pratiques exemplaires en matière d'authentification et de gestion de session? Je peux penser à deux façons d'envisager d'aborder le problème.

  1. ne le traitent pas différemment que l'authentification avec une application web régulière en supposant que L'API et L'UI ont le même domaine d'origine.

    ce serait probablement implique d'avoir un cookie de session, un stockage de session côté serveur et probablement un terminal D'API de session que l'interface web authentifiée peut atteindre pour obtenir des informations utilisateur à jour pour aider à la personnalisation ou peut-être même déterminer les rôles/capacités du côté client. Le serveur imposerait toujours des règles protégeant l'accès aux données.bien sûr, L'interface utilisateur utiliserait simplement cette information pour personnaliser l'expérience.

  2. traitez-le comme un client tiers utiliser une API publique et authentifier avec une sorte de système de token similaire à OAuth. Ce mécanisme de token serait utilisé par L'interface utilisateur client pour authentifier chaque requête faite à l'API du serveur.

Je ne suis pas vraiment un expert ici, mais le numéro 1 semble tout à fait suffisant pour la grande majorité des cas, mais j'aimerais vraiment entendre des opinions plus expérimentées.

229
demandé sur Robert Koritnik 2014-01-07 07:13:48

3 réponses

cette question a été abordée, sous une forme légèrement différente, en détail ici:

"151950920 De" Repos "Authentification 151960920"

mais ceci l'adresse du côté du serveur. Regardons du côté client. Mais avant cela, il y a un prélude important:

la cryptographie Javascript est sans espoir

L'article de Matasano sur ceci est célèbre, mais les leçons qu'il contient sont assez importants:

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

pour résumer:

  • un homme-dans-l'attaque du milieu peut trivialement remplacer votre code de crypto Par <script> function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script>
  • une attaque man-in-the-middle est triviale contre une page qui sert n'importe quelle ressource sur une connexion non-SSL.
  • une fois que vous avez SSL, vous utilisez une vraie crypto de toute façon.

et d'ajouter un corollaire:

  • une attaque XSS réussie peut entraîner l'exécution du code par un attaquant sur le navigateur de votre client, même si vous utilisez SSL - donc même si vous avez toutes les hatch battues vers le bas, votre navigateur crypto peut toujours échouer si votre attaquant trouve un moyen d'exécuter n'importe quel code javascript sur le navigateur de quelqu'un d'autre.

cela rend beaucoup de repos les schémas d'authentification impossible ou stupide si vous avez l'intention d'utiliser un client JavaScript. Voyons!

HTTP Basic Auth

tout d'abord, HTTP Basic Auth. Le plus simple des schémas: il suffit de passer un nom et un mot de passe avec chaque requête.

cela, bien sûr, nécessite absolument SSL, parce que vous passez un nom codé Base64 (réversiblement) et un mot de passe avec chaque requête. N'importe qui écoutant sur la ligne pourrait extraire nom d'utilisateur et mot de passe trivialement. La plupart des arguments" Basic Auth is insecure "viennent d'un endroit de" Basic Auth over HTTP " ce qui est une idée terrible.

le navigateur fournit la prise en charge HTTP Basic Auth dans le paquet, mais elle est aussi laide que sin et vous ne devriez probablement pas l'utiliser pour votre application. L'alternative, cependant, est de cacher le nom d'utilisateur et le mot de passe dans JavaScript.

c'est la solution la plus reposante. Le serveur n'exige aucune connaissance d'état que ce soit et authentifie chaque interaction individuelle avec l'utilisateur. Certains adeptes du repos (principalement des hommes de paille) insistent sur le fait que le maintien de n'importe quelle sorte d'état est hérétique et va mousser à la bouche si vous pensez à n'importe quelle autre méthode d'authentification. Il y a des avantages théoriques à ce genre de normes-la conformité - il est soutenu par Apache hors de la boîte - vous pourriez stocker vos objets en tant que fichiers dans des dossiers protégés par .htaccess si votre cœur désirée!

Le problème ? Vous mettez en cache du côté client un nom d'utilisateur et un mot de passe. Cela donne evil.ru une meilleure fissure - même la plus élémentaire des vulnérabilités XSS pourrait amener le client à transmettre son nom d'utilisateur et son mot de passe à un serveur malveillant. Vous pouvez essayer d'atténuer ce risque en tapant sur le clavier et en salant le mot de passe, mais rappelez-vous: la cryptographie JavaScript est sans espoir . Vous pouvez atténuer ce risque en laissant le support de base de L'auteur du navigateur, mais.. laids comme le péché, comme mentionné plus tôt.

HTTP Digest Auth

Est l'authentification Digest possible avec jQuery?

Un plus "secure" auth, c'est une demande/réponse de hachage défi. Sauf JavaScript Crypto est sans espoir , donc il ne fonctionne que sur SSL et vous devez toujours mettre en cache le nom d'utilisateur et le mot de passe du côté du client, ce qui le rend plus compliqué que HTTP Basic Auth mais pas plus sécurisez .

interrogation authentification avec paramètres de Signature supplémentaires.

un autre auth plus "sécurisé", où vous cryptez vos paramètres avec des données nonce et timing (pour vous protéger contre les attaques répétées et timing) et envoyez le. Un des meilleurs exemples de cela est le protocole OAuth 1.0, qui est, pour autant que je sache, une façon assez rudimentaire d'implémenter l'authentification sur un serveur REST.

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

Oh, mais il n'y a pas de clients OAuth 1.0 Pour JavaScript. Pourquoi?

la cryptographie JavaScript est sans espoir , rappelez-vous. JavaScript ne peut pas participer à OAuth 1.0 sans SSL, et vous devez encore stocker le nom d'utilisateur et le mot de passe du client localement - ce qui met cela dans la même catégorie que Digest Auth - c'est plus compliqué que HTTP Basic Auth mais c'est pas plus sécurisez .

Jeton

l'utilisateur envoie un nom d'utilisateur et un mot de passe, et en échange obtient un token qui peut être utilisé pour authentifier des requêtes.

c'est légèrement plus sûr que HTTP Basic Auth, car dès que la transaction nom d'utilisateur/mot de passe est terminée, vous pouvez jeter les données sensibles. C'est aussi moins reposant, car les tokens constituent "l'état" et rendent l'implémentation du serveur plus compliquée.

SSL Still

le hic, cependant, est que vous devez toujours envoyer ce nom d'Utilisateur initial et mot de passe pour obtenir un token. Les informations sensibles touchent toujours votre JavaScript compromissible.

pour protéger les informations d'identification de votre utilisateur, vous devez toujours garder les attaquants hors de votre JavaScript, et vous avez toujours besoin d'envoyer un nom d'utilisateur et un mot de passe par le fil. SSL requis.

Expiration Du Jeton

c'est commun pour appliquer des politiques de token comme " hey, quand ce token a été autour trop longtemps, le jeter et faire l'utilisateur authentifier à nouveau."ou "je suis presque sûr que la seule adresse IP autorisée pour utiliser ce token est XXX.XXX.XXX.XXX ". Nombre de ces politiques sont très bonnes idées.

feu de cheminée

cependant, l'utilisation D'un token sans SSL reste vulnérable à une attaque appelée "sidejacking": http://codebutler.github.io/firesheep /

L'attaquant ne reçoit pas les informations d'identification de votre utilisateur, mais ils peuvent toujours prétendre être votre utilisateur, ce qui peut être assez mauvais.

tl;dr: L'envoi de jetons non cryptés sur le fil signifie que les attaquants peuvent facilement attraper ces jetons et prétendre être votre utilisateur. FireSheep est un programme qui rend cela très facile.

Un Autre, Plus Secure Zone

plus l'application que vous utilisez est grande, plus elle est dure est de s'assurer absolument qu'ils ne seront pas en mesure d'injecter un code qui change la façon dont vous traitez les données sensibles. Faites-vous absolument confiance à votre CDN? Vos annonceurs? Votre propre base de code?

commun pour les détails de carte de crédit et moins commun pour le nom d'utilisateur et le mot de passe - certains responsables de la mise en œuvre conservent la "saisie de données sensibles" sur une page séparée du reste de leur application, une page qui peut être étroitement contrôlée et verrouillée de la meilleure façon possible, de préférence une page qui est difficile pour phish utilisateurs.

Cookie (signifie simplement Token)

il est possible (et courant) de placer le token d'authentification dans un cookie. Cela ne change aucune des propriétés d'auth avec le token, c'est plus pratique. Tous ces arguments s'appliquent toujours.

Session (toujours moyen de Jeton)

session Auth n'est qu'une authentification de jeton, mais avec quelques différences qui le font paraître comme une chose légèrement différente:

  • les utilisateurs commencent avec un token non authentifié.
  • le backend maintient un objet 'state' qui est lié au token d'un utilisateur.
  • le token est fourni dans un cookie.
  • l'environnement d'application résume les détails loin de vous.

mis à part cela, il n'est pas différent de Token Auth, vraiment.

cela va encore plus loin d'une implémentation reposante - avec les objets de l'état, vous allez de plus en plus loin sur le chemin du simple Vieux RPC sur un serveur de l'état.

OAuth 2.0

OAuth 2.0 se penche sur le problème de "comment un logiciel a donne-t-il au logiciel B l'accès aux données de L'utilisateur X sans que le logiciel B ait accès aux identifiants de connexion de L'utilisateur X."

la mise en œuvre est très juste un moyen standard pour un utilisateur de obtenir un token, et puis pour un service tiers de faire "yep, cet utilisateur et ce token correspondent, et vous pouvez obtenir certaines de leurs données de nous maintenant."

fondamentalement, cependant, OAuth 2.0 est juste un protocole symbolique. Il présente les mêmes propriétés que les autres protocoles de tokens - vous avez encore besoin de SSL pour protéger ces tokens - il change simplement la façon dont ces tokens sont générés.

il y a deux façons que OAuth 2.0 peut vous aider:

  • fourniture D'une authentification/Information à autrui
  • obtention D'une authentification/Information d'autrui

mais quand il s'agit de ça, vous êtes juste... à l'aide de jetons.

retournez à votre question

donc, la question que vous posez est " devrais-je stocker mon token dans un cookie et avoir la gestion de session automatique de mon environnement prendre soin des détails, ou devrais-je stocker mon token en Javascript et gérer ces détails moi-même?"

Et la réponse est: faites ce qui vous rend heureux .

la chose à propos de la gestion automatique des sessions, cependant, c'est qu'il y a beaucoup de magie qui se passe dans les coulisses pour vous. Souvent, il est plus agréable d'être dans le contrôle de ces informations.

je suis 21 SSL est oui

l'autre réponse est: utilisez https pour tout ou les brigands voleront les mots de passe et les jetons de vos utilisateurs.

387
répondu Curtis Lassam 2017-05-23 11:55:03

vous pouvez augmenter la sécurité dans le processus d'authentification en utilisant JWT (JSON Web Tokens) et SSL/HTTPS.

L'identifiant de base de L'Auth / Session peut être volé via:

  • MITM attack (Man-In-the-Middle) - without SSL /HTTPS
  • un intrus ayant accès à l'ordinateur d'un utilisateur
  • XSS

en utilisant JWT vous êtes chiffrer les détails d'authentification de l'utilisateur et stocker dans le client, et l'envoyer avec chaque demande à L'API, où le serveur/API valide le token. il ne peut pas être déchiffré/lu sans la clé privée (que le serveur/API stocke secrètement) Lire mise à jour .

le nouveau débit (plus sûr) serait:

Login

  • utilisateur se connecte et envoie les identifiants de connexion à L'API (sur SSL/HTTPS)
  • API reçoit des informations d'identification de connexion
  • si valide:
    • enregistrer une nouvelle session dans la base de données Lire la mise à jour
    • Chiffrer ID Utilisateur, ID de Session, l'adresse IP, l'horodatage, etc. dans un JWT avec une clé privée.
  • L'API
  • renvoie le JWT au client (plus de SSL/HTTPS)
  • le Client reçoit le token JWT et stocke sur place / cookie

Chaque requête à l'API

  • L'utilisateur envoie une requête HTTP à L'API (sur SSL/HTTPS) avec le token JWT stocké dans L'en-tête HTTP
  • L'API lit l'en-tête HTTP et déchiffre le token JWT avec sa clé privée
  • valide L'API JWT token, associe L'adresse IP de la requête HTTP à celle de la JWT token et vérifie si la session a expiré
  • si valide:
    • Retour de l'intervention avec le contenu demandé
  • si invalide:
    • exception de lancer (403 / 401)
    • intrusion D'un indicateur dans le système
    • envoyer un e-mail d'avertissement à l'utilisateur.

mise à jour 30.07.15:

JWT payload / claims peut en fait être lu sans la clé privée (secret) et il n'est pas sûr de le stocker dans un stockage local. Je suis désolé pour ces fausses déclarations. Cependant, ils semblent travailler sur un jwe standard (JSON Web Encryption) .

j'ai implémenté ceci en stockant les revendications (userID, exp) dans un JWT, signé avec une clé privée (secret), L'API/backend ne connaît et ne stocke Qu'un cookie HttpOnly sécurisé sur le client. De cette façon, il ne peut pas être lu via XSS et ne peut pas être manipulé, sinon la JWT échoue à la vérification de la signature. De plus, en utilisant un cookie sécurisé HttpOnly , vous vous assurez que le cookie est envoyé uniquement via des requêtes HTTP (non accessibles à script) et uniquement via une connexion sécurisée (HTTPS).

mise à jour 17.07.16:

les Tjsf sont par nature apatrides. Cela signifie qu'ils s'invalident/expirent eux-mêmes. En ajoutant le SessionID dans les revendications du token vous le rendez stateful, parce que sa validité ne dépend plus seulement de la vérification de la signature et de la date d'expiration, il dépend aussi de l'état de la session sur le serveur. Cependant le bon côté est que vous pouvez invalider les tokens/sessions facilement, ce que vous ne pouviez pas avant avec les JWTS apatrides.

45
répondu Gaui 2016-07-17 21:18:25

j'opterais pour le second, le système de token.

le Saviez-vous à propos de braise-auth ou braise-simple-auth ? Ils utilisent tous les deux le système basé sur les jeton, comme ember-simple-auth déclare:

une bibliothèque légère et discrète pour implémenter des tokens basés l'authentification dans les Braises.js applications. http://ember-simple-auth.simplabs.com

Ils ont la gestion de session, et sont faciles à brancher dans les projets existants.

il y a aussi une version D'ember App Kit exemple d'ember-simple-auth: exemple de travail d'ember-app-kit utilisant ember-simple-auth pour l'authentification OAuth2.

8
répondu DelphiLynx 2014-01-07 11:28:25