web-dev-qa-db-fra.com

Meilleures pratiques pour l'authentification et l'autorisation dans Angular sans enfreindre les principes RESTful?

J'ai lu pas mal de fils SO sur l'authentification et l'autorisation avec REST et Angular, mais je n'ai toujours pas l'impression d'avoir une excellente solution pour ce que j'espère faire. Pour certains antécédents, je prévois de créer une application dans AngularJS où je veux prendre en charge:

  1. Accès invité limité
  2. Accès basé sur les rôles à l'application une fois authentifié
  3. Authentification via les API

Tous les appels à l'API REST devront se faire via SSL. Je voudrais créer l'application sans enfreindre les principes RESTful, à savoir ne pas conserver l'état de session stocké sur le serveur. Bien sûr, tout ce qui se fait vis-à-vis de l’autorisation côté client doit être renforcé côté serveur. Comme nous devons passer l’état entier à chaque demande, je sais que je dois passer une sorte de jeton pour que le le serveur principal recevant la demande REST peut à la fois authentifier et autoriser l'appel.

Cela dit, ma principale question concerne l'authentification - quelles sont les meilleures pratiques ici? Il semble qu'il y ait beaucoup d'approches différentes discutées, voici quelques-unes que j'ai trouvées:

Une question similaire a été posée ( authentification d'application AngularJS ), mais à moins que je ne comprenne mal la réponse, cela semble impliquer qu'une session serveur doit être utilisée, ce qui enfreint les principes RESTful.

Ma principale préoccupation avec Amazon AWS et l'article de George Reese est qu'il semble supposer que le consommateur est un programme plutôt qu'un utilisateur final. Un secret partagé peut être délivré à l'avance à un programmeur, qui peut ensuite l'utiliser pour coder les appels ici. Ce n'est pas le cas ici - je dois appeler l'API REST depuis l'application au nom de l'utilisateur).

Cette approche serait-elle suffisante? Disons que j'ai une ressource de session:

POST/api/session

Créer une nouvelle session pour un utilisateur

Pour créer une session, vous devez POST un objet JSON contenant le "nom d'utilisateur" et le "mot de passe").

{
    "email" : "[email protected]",
    "password" : "password"
}

Exemple de boucle

curl -v -X POST --data '{"username":"[email protected]","password":"password"}' "https://app.example.com/api/session" --header "Content-Type:application/json"

Réponse

HTTP/1.1 201 Created {
    "session": {
        "id":"520138ccfa4634be08000000",
        "expires":"2014-03-20T17:56:28+0000"
    }
}

Codes d'état

  • 201 - Création, nouvelle session établie
  • 400 - Mauvaise demande, l'objet JSON n'est pas valide ou les informations requises sont manquantes
  • 401 - Combo non autorisé, Vérifier e-mail/mot de passe
  • 403 - Accès refusé, compte désactivé ou licence non valide

Je laisse de côté les détails HATEOAS pour plus de clarté. Sur le backend, il y aurait une nouvelle clé de session à durée limitée créée et associée à l'utilisateur. Sur les demandes suivantes, je pourrais transmettre ceci dans le cadre des en-têtes HTTP:

Authorization: MyScheme 520138ccfa4634be08000000 

Ensuite, les serveurs principaux seraient chargés de digérer cela hors de la demande, de trouver l'utilisateur associé et d'appliquer les règles d'autorisation pour la demande. Il devrait probablement également mettre à jour l'expiration de la session.

Si tout cela se produit via SSL, est-ce que je laisse la porte ouverte à tout type d'attaques contre lesquelles je devrais me protéger? Vous pouvez essayer de deviner les clés de session et les placer dans l'en-tête, donc je suppose que je pourrais également ajouter un utilisateur GUID à la clé de session pour empêcher davantage les attaques par force brute.

Cela fait quelques années que je n'ai pas programmé activement et je ne fais que reprendre le swing ici. Toutes mes excuses si je suis obtus ou que je réinvente inutilement la roue, dans l'espoir de faire fonctionner mes idées par la communauté ici sur la base de mes lectures jusqu'à présent et de voir si elles réussissent le test décisif.

41
austrum

Lorsque quelqu'un pose une question sur l'authentification REST, je m'en remets aux services Web d'Amazon et je suggère essentiellement de "faire cela". Pourquoi? Parce que, du point de vue de la "sagesse des foules", AWS résout le problème. problème, est largement utilisé, fortement analysé et vérifié par des gens qui connaissent et se soucient beaucoup plus que la plupart de ce qui fait une demande sécurisée que la plupart. Et la sécurité est un bon endroit pour "ne pas réinventer la roue". En termes de "épaules à stand on ", vous pouvez faire pire que AWS.

Maintenant, AWS n'utilise pas de technique de jeton, il utilise plutôt un hachage sécurisé basé sur des secrets partagés et la charge utile. Il s'agit sans doute d'une implémentation plus compliquée (avec tous ses processus de normalisation, etc.).

Mais ça marche.

L'inconvénient est qu'il nécessite que votre application conserve le secret partagé des personnes (c'est-à-dire le mot de passe), et que le serveur ait également accès à cette version en texte brut du mot de passe. Cela signifie généralement que le mot de passe est stocké crypté, puis décrypté comme il convient. Et cela invite à une complexité encore plus grande de la gestion des clés et d'autres choses côté serveur par rapport à la technique de hachage sécurisé.

Le plus gros problème, bien sûr, avec toute technique de passage de jeton est les attaques Man in the Middle et les attaques par rejeu. SSL les atténue principalement, naturellement.

Bien sûr, vous devriez également considérer la famille OAuth, qui a ses propres problèmes, notamment d'interopérabilité, mais si ce n'est pas un objectif principal, les techniques sont certainement valides.

Pour votre application, le bail de jetons n'est pas un gros problème. Votre application devra toujours fonctionner dans le délai du bail ou être en mesure de la renouveler. Pour ce faire, il devra soit conserver les informations d'identification de l'utilisateur, soit les ré-inviter pour cela. Traitez simplement le jeton comme une ressource de première classe, comme toute autre chose. Si possible, essayez d'associer d'autres informations à la demande et de les regrouper dans le jeton (signature du navigateur, adresse IP), juste pour appliquer une localité.

Vous êtes toujours ouvert à des problèmes (potentiels) de relecture, où la même demande peut être envoyée deux fois. Avec une implémentation de hachage typique, un horodatage fait partie de la signature qui peut encadrer la durée de vie de la demande. Cela est résolu différemment dans ce cas. Par exemple, chaque demande peut être envoyée avec un ID de série ou un GUID et vous pouvez enregistrer que la demande a déjà été lue pour l'empêcher de se reproduire. Différentes techniques pour cela.

15
Will Hartung

Voici un article incroyable sur les services d'authentification et de connexion construits avec angular.

https://medium.com/opinionated-angularjs/7bbf0346acec

9
Sten Muchow

Cette SO question fait un bon travail de résumer ma compréhension de REST

Les sessions violent-elles vraiment RESTfulness?

Si vous stockez un jeton dans une session, vous créez toujours un état côté serveur (c'est un problème car cette session n'est généralement stockée que sur le même serveur, cela peut être atténué avec des sessions persistantes ou d'autres solutions).

J'aimerais savoir quel est votre raisonnement pour créer un service RESTful car peut-être que ce n'est pas vraiment une grande préoccupation.

Si vous envoyez un jeton dans le corps avec chaque demande (puisque tout est crypté avec SSL, cela ne pose aucun problème), vous pouvez avoir un nombre illimité de serveurs (à charge équilibrée) qui traitent la demande sans aucune connaissance préalable de l'état.

Pour faire court, je pense que viser des implémentations RESTful est un bon objectif, mais être purement apatride crée certainement une couche supplémentaire de complexité en ce qui concerne l'authentification et la vérification des autorisations.

Jusqu'à présent, j'ai commencé à construire mes back-ends avec REST à l'esprit, en créant des URI qui ont du sens et en utilisant les bons verbes HTTP, mais j'utilise toujours un jeton dans une session pour la simplicité de l'authentification (lorsque vous n'utilisez pas plusieurs serveurs).

J'ai lu les liens que vous avez publiés, celui d'AngularJS semble se concentrer uniquement sur le client et ne semble pas adresser explicitement le serveur dans cet article, il fait un lien vers un autre (je ne suis pas un Node utilisateur alors pardonnez-moi si mon interprétation est erronée ici) mais il semble que le serveur compte sur le client pour lui dire quel niveau d'autorisation il a, ce qui n'est clairement pas une bonne idée.

0
shaunhusain