Lors de la création d'applications de style SPA à l'aide de cadres tels que Angular, Ember, React, etc., que pensent les gens des meilleures pratiques d'authentification et de gestion de session? Je peux penser à deux façons d'envisager d'aborder le problème.
Ne le traitez pas différemment de l'authentification avec une application Web classique en supposant que l'API et l'interface utilisateur ont le même domaine d'origine.
Cela impliquerait probablement d'avoir un cookie de session, un stockage de session côté serveur et probablement un point de terminaison d'API de session que l'interface utilisateur Web authentifiée peut atteindre pour obtenir les informations utilisateur actuelles pour aider à la personnalisation ou peut-être même déterminer les rôles / capacités du côté client. Le serveur appliquerait toujours des règles protégeant l'accès aux données bien sûr, l'interface utilisateur utiliserait simplement ces informations pour personnaliser l'expérience.
Traitez-le comme n'importe quel client tiers utilisant une API publique et authentifiez-vous avec une sorte de système de jetons similaire à OAuth. Ce mécanisme de jeton serait utilisé par l'interface utilisateur du client pour authentifier chaque demande adressée à l'API du serveur.
Je ne suis pas vraiment un expert ici, mais # 1 semble être complètement suffisant pour la grande majorité des cas, mais j'aimerais vraiment entendre des opinions plus expérimentées.
la source
Réponses:
Cette question a été abordée, sous une forme légèrement différente, longuement, ici:
Authentification RESTful
Mais cela résout le problème du côté serveur. Examinons cela du côté client. Avant de faire cela, cependant, il y a un prélude important:
Javascript Crypto est sans espoir
L'article de Matasano à ce sujet est célèbre, mais les leçons qu'il contient sont assez importantes:
https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/
Résumer:
<script> function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script>
Et pour ajouter un corollaire à moi:
Cela rend beaucoup de schémas d'authentification RESTful impossibles ou stupides si vous avez l'intention d'utiliser un client JavaScript. Regardons!
Authentification HTTP de base
Tout d'abord, HTTP Basic Auth. Le plus simple des schémas: passez simplement un nom et un mot de passe à chaque demande.
Bien sûr, cela nécessite absolument SSL, car vous transmettez un nom et un mot de passe encodés en Base64 (réversiblement) à chaque demande. Quiconque écoute sur la ligne peut extraire trivialement le nom d'utilisateur et le mot de passe. La plupart des arguments "Basic Auth is unsecure" proviennent d'un endroit de "Basic Auth over HTTP" qui est une idée horrible.
Le navigateur fournit un support d'authentification HTTP de base intégré, mais il est laid comme un péché et vous ne devriez probablement pas l'utiliser pour votre application. Cependant, l'alternative consiste à cacher le nom d'utilisateur et le mot de passe en JavaScript.
C'est la solution la plus RESTful. Le serveur ne nécessite aucune connaissance de l'état et authentifie chaque interaction individuelle avec l'utilisateur. Certains amateurs de REST (principalement des hommes de paille) insistent sur le fait que le maintien de toute sorte d'état est une hérésie et moussera à la bouche si vous pensez à une autre méthode d'authentification. Il existe des avantages théoriques à ce type de conformité aux normes - il est pris en charge par Apache prêt à l'emploi - vous pouvez stocker vos objets sous forme de fichiers dans des dossiers protégés par des fichiers .htaccess si votre cœur le souhaite!
Le problème ? Vous mettez en cache côté client un nom d'utilisateur et un mot de passe. Cela donne à evil.ru une meilleure solution: même les vulnérabilités les plus élémentaires de XSS pourraient 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 hachant et en salant le mot de passe, mais rappelez-vous: JavaScript Crypto est sans espoir . Vous pouvez atténuer ce risque en le laissant à la prise en charge de l'authentification de base du navigateur, mais .. laid comme un péché, comme mentionné précédemment.
HTTP Digest Auth
L'authentification Digest est-elle possible avec jQuery?
Une authentification plus "sécurisée", c'est un défi de hachage de demande / réponse. Sauf que JavaScript Crypto est sans espoir , il ne fonctionne que sur SSL et vous devez toujours mettre en cache le nom d'utilisateur et le mot de passe côté client, ce qui le rend plus compliqué que HTTP Basic Auth mais pas plus sécurisé .
Authentification de requête avec des paramètres de signature supplémentaires.
Une autre authentification plus "sécurisée", où vous cryptez vos paramètres avec des données nonce et de synchronisation (pour vous protéger contre les attaques répétées et de synchronisation) et envoyez le. L'un des meilleurs exemples de cela est le protocole OAuth 1.0, qui est, pour autant que je sache, un moyen assez efficace pour 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?
JavaScript Crypto est désespéré , rappelez-vous. JavaScript ne peut pas participer à OAuth 1.0 sans SSL, et vous devez toujours stocker le nom d'utilisateur et le mot de passe du client localement - ce qui le place dans la même catégorie que Digest Auth - c'est plus compliqué que HTTP Basic Auth mais ce n'est pas plus sécurisé .
Jeton
L'utilisateur envoie un nom d'utilisateur et un mot de passe, et en échange obtient un jeton qui peut être utilisé pour authentifier les demandes.
Ceci est légèrement plus sécurisé que HTTP Basic Auth, car dès que la transaction de nom d'utilisateur / mot de passe est terminée, vous pouvez supprimer les données sensibles. Il est également moins RESTful, car les jetons constituent un "état" et rendent l'implémentation du serveur plus compliquée.
SSL toujours
Le hic, cependant, est que vous devez toujours envoyer ce nom d'utilisateur et ce mot de passe initiaux pour obtenir un jeton. Les informations sensibles touchent toujours votre JavaScript compromis.
Pour protéger les informations d'identification de votre utilisateur, vous devez toujours garder les attaquants hors de votre JavaScript, et vous devez toujours envoyer un nom d'utilisateur et un mot de passe sur le câble. SSL requis.
Expiration du jeton
Il est courant d'appliquer des stratégies de jeton telles que «hé, lorsque ce jeton existe depuis trop longtemps, jetez-le et faites-vous authentifier à nouveau». ou "Je suis pratiquement sûr que la seule adresse IP autorisée à utiliser ce jeton est
XXX.XXX.XXX.XXX
". Beaucoup de ces politiques sont de très bonnes idées.Firesheeping
Cependant, l'utilisation d'un jeton sans SSL est toujours vulnérable à une attaque appelée «sidejacking»: http://codebutler.github.io/firesheep/
L'attaquant n'obtient pas les informations d'identification de votre utilisateur, mais il peut toujours prétendre être votre utilisateur, ce qui peut être assez mauvais.
tl; dr: L'envoi de jetons non chiffrés via le câble signifie que les attaquants peuvent facilement attraper ces jetons et prétendre être votre utilisateur. FireSheep est un programme qui rend cela très simple.
Une zone séparée et plus sécurisée
Plus l'application que vous exécutez est grande, plus il est difficile de garantir absolument qu'elle ne pourra pas injecter du code qui modifie la façon dont vous traitez les données sensibles. Faites-vous entièrement confiance à votre CDN? Vos annonceurs? Votre propre base de code?
Commun pour les détails de la carte de crédit et moins commun pour le nom d'utilisateur et le mot de passe - certains implémenteurs conservent la `` saisie de données sensibles '' sur une page distincte du reste de leur application, une page qui peut être étroitement contrôlée et verrouillée le mieux possible, de préférence une qui est difficile à hameçonner avec les utilisateurs.
Cookie (signifie simplement Token)
Il est possible (et courant) de placer le jeton d'authentification dans un cookie. Cela ne change aucune des propriétés d'auth avec le jeton, c'est plus une chose pratique. Tous les arguments précédents s'appliquent toujours.
Session (signifie toujours juste Token)
L'authentification de session n'est qu'une authentification par jeton, mais avec quelques différences qui la font paraître quelque chose de légèrement différent:
Hormis cela, cependant, ce n'est pas différent de Token Auth, vraiment.
Cela s'éloigne encore plus d'une implémentation RESTful - avec les objets d'état, vous allez de plus en plus loin sur le chemin du RPC ordinaire sur un serveur avec état.
OAuth 2.0
OAuth 2.0 examine le problème de "Comment le 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 informations de connexion de l'utilisateur X".
L'implémentation est tout simplement un moyen standard pour un utilisateur d'obtenir un jeton, puis pour un service tiers d'aller "oui, cet utilisateur et ce jeton correspondent, et vous pouvez obtenir certaines de leurs données maintenant".
Fondamentalement, cependant, OAuth 2.0 n'est qu'un protocole symbolique. Il présente les mêmes propriétés que les autres protocoles de jetons - vous avez toujours besoin de SSL pour protéger ces jetons - il modifie simplement la façon dont ces jetons sont générés.
OAuth 2.0 peut vous aider de deux manières:
Mais en fin de compte, vous utilisez simplement ... des jetons.
Retour à votre question
Ainsi, la question que vous posez est "dois-je stocker mon jeton dans un cookie et faire en sorte que la gestion automatique des sessions de mon environnement s'occupe des détails, ou dois-je stocker mon jeton en Javascript et gérer moi-même ces détails?"
Et la réponse est: faites tout 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. Il est souvent plus agréable de contrôler vous-même ces détails.
J'ai 21 ans donc 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.
la source
It's also less RESTful, as tokens constitute "state and make the server implementation more complicated."
(1) REST requiert que le serveur soit sans état. Un côté client stocké par jeton ne représente pas l'état de manière significative pour le serveur. (2) Un code côté serveur légèrement plus compliqué n'a rien à voir avec RESTfulness.lol_nope_send_it_to_me_instead
J'ai adoré le nom de cette fonction: DVous pouvez augmenter la sécurité du processus d'authentification en utilisant JWT (JSON Web Tokens) et SSL / HTTPS.
L'ID d'authentification / session de base peut être volé via:
En utilisant JWT, vous cryptez les détails d'authentification de l'utilisateur et les stockez dans le client, et vous les envoyez avec chaque demande à l'API, où le serveur / API valide le jeton.
Il ne peut pas être déchiffré / lecture sans la clé privée (que le serveur / API stocke secrètement)mises à jour Lire .Le nouveau flux (plus sécurisé) serait:
S'identifier
Chaque demande à l'API
Mise à jour 30.07.15:
La charge utile / les revendications JWT peuvent en fait être lues sans la clé privée (secrète) et il n'est pas sûr de la stocker dans localStorage. Je suis désolé pour ces fausses déclarations. Cependant, ils semblent fonctionner sur une norme JWE (JSON Web Encryption) .
J'ai implémenté cela en stockant les revendications (userID, exp) dans un JWT, je l'ai signé avec une clé privée (secrète) que l'API / backend ne connaît que et l'a stocké en tant que 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 le JWT échoue à la vérification de signature. De plus, en utilisant un cookie HttpOnly sécurisé , vous vous assurez que le cookie est envoyé uniquement via des requêtes HTTP (non accessible au script) et uniquement via une connexion sécurisée (HTTPS).
Mise à jour le 17.07.16:
Les JWT sont par nature apatrides. Cela signifie qu'ils s'invalident / expirent eux-mêmes. En ajoutant le SessionID dans les revendications du jeton, vous le rendez avec état, car sa validité ne dépend plus uniquement de la vérification de la signature et de la date d'expiration, il dépend également de l'état de la session sur le serveur. Cependant, l'avantage est que vous pouvez facilement invalider des jetons / sessions, ce que vous ne pouviez pas auparavant avec des JWT sans état.
la source
J'irais pour le deuxième, le système de jetons.
Connaissiez-vous ember-auth ou ember-simple-auth ? Ils utilisent tous les deux le système basé sur des jetons, comme les états ember-simple-auth:
Ils ont la gestion des sessions et sont faciles à connecter aux projets existants.
Il existe également un exemple de version Ember App Kit d'ember-simple-auth: Exemple de travail d'ember-app-kit utilisant ember-simple-auth pour l'authentification OAuth2.
la source