Authentification RESTful


745

Que signifie l'authentification RESTful et comment fonctionne-t-elle? Je ne trouve pas un bon aperçu sur Google. Ma seule compréhension est que vous passez la clé de session (remeberal) dans l'URL, mais cela pourrait être horriblement faux.


3
Quand je google Restful Authentication je trouve une douzaine de plugins RoR. Je suppose que ce n'est PAS ce que vous recherchez. Sinon RoR, alors quelle langue? Quel serveur web?
S.Lott

2
Ce ne sera pas horriblement mal si vous utilisez HTTPS. La requête HTTP complète avec l'URL serait cryptée.
Bharat Khatri

4
@BharatKhatri: Oui, ce serait le cas. Je ne transmettrais jamais d'informations sensibles dans l'URL visible par l'utilisateur. Ces informations sont beaucoup plus susceptibles de fuir à des fins pratiques. HTTPS ne peut pas aider en cas de fuite accidentelle.
Jo So

2
@jcoffland: Qu'entendez-vous par véritable authentification RESTful? Je suis intéressé car je viens de mettre en œuvre la troisième voie à partir de la réponse acceptée, mais je ne suis pas satisfait (je n'aime pas le paramètre supplémentaire dans l'URL).
BlueLettuce16

4
certaines personnes utilisent jwt.io/introduction pour résoudre ce problème. Je fais des recherches à ce sujet en ce moment pour résoudre mon cas: stackoverflow.com/questions/36974163/… >> J'espère que cela fonctionnera bien.
toha

Réponses:


586

Comment gérer l'authentification dans une architecture client-serveur RESTful est un sujet de débat.

Généralement, cela peut être réalisé, dans le monde SOA sur HTTP via:

  • Authentification de base HTTP sur HTTPS;
  • Cookies et gestion de session;
  • Jeton dans les en-têtes HTTP (par exemple OAuth 2.0 + JWT);
  • Authentification de requête avec des paramètres de signature supplémentaires.

Vous devrez adapter, ou encore mieux mélanger ces techniques, pour correspondre au mieux à votre architecture logicielle.

Chaque schéma d'authentification a ses propres avantages et inconvénients, en fonction de l'objectif de votre politique de sécurité et de votre architecture logicielle.

Authentification de base HTTP sur HTTPS

Cette première solution, basée sur le protocole HTTPS standard, est utilisée par la plupart des services Web.

GET /spec.html HTTP/1.1
Host: www.example.org
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Il est facile à implémenter, disponible par défaut sur tous les navigateurs, mais présente certains inconvénients connus, comme la terrible fenêtre d'authentification affichée sur le navigateur, qui persistera (il n'y a pas de fonctionnalité de type LogOut ici), une consommation supplémentaire de CPU côté serveur, et le fait que le nom d'utilisateur et le mot de passe sont transmis (via HTTPS) au serveur (il devrait être plus sûr de laisser le mot de passe uniquement côté client, lors de la saisie au clavier, et être stocké en tant que hachage sécurisé sur le serveur) .

Nous pouvons utiliser l' authentification Digest , mais elle nécessite également HTTPS, car elle est vulnérable aux attaques MiM ou Replay , et est spécifique à HTTP.

Session via les cookies

Pour être honnête, une session gérée sur le serveur n'est pas vraiment sans état.

Une possibilité pourrait être de conserver toutes les données dans le contenu des cookies. Et, par conception, le cookie est géré côté serveur (le client, en fait, n'essaie même pas d'interpréter ces données de cookie: il les restitue simplement au serveur à chaque demande successive). Mais ces données de cookie sont des données d'état d'application, donc le client doit les gérer, pas le serveur, dans un monde sans état pur.

GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: theme=light; sessionToken=abc123

La technique des cookies elle-même est liée à HTTP, donc ce n'est pas vraiment RESTful, qui devrait être indépendant du protocole, à mon humble avis. Il est vulnérable aux attaques MiM ou Replay .

Accordé via Token (OAuth2)

Une alternative consiste à placer un jeton dans les en-têtes HTTP afin que la demande soit authentifiée. C'est ce que fait OAuth 2.0, par exemple. Voir la RFC 6749 :

 GET /resource/1 HTTP/1.1
 Host: example.com
 Authorization: Bearer mF_9.B5f-4.1JqM

En bref, cela est très similaire à un cookie et souffre des mêmes problèmes: pas apatride, s'appuyant sur les détails de transmission HTTP et soumis à de nombreuses faiblesses de sécurité - y compris MiM et Replay - ne doit donc être utilisé que via HTTPS. En règle générale, un JWT est utilisé comme un jeton.

Authentification de requête

L'authentification de requête consiste à signer chaque demande RESTful via certains paramètres supplémentaires sur l'URI. Voir cet article de référence .

Il a été défini comme tel dans cet article:

Toutes les requêtes REST doivent être authentifiées en signant les paramètres de requête triés dans l'ordre alphabétique en minuscules en utilisant les informations d'identification privées comme jeton de signature. La signature doit avoir lieu avant que l'URL n'encode la chaîne de requête.

Cette technique est peut-être la plus compatible avec une architecture sans état, et peut également être implémentée avec une gestion de session légère (en utilisant des sessions en mémoire au lieu de la persistance de la base de données).

Par exemple, voici un exemple d'URI générique à partir du lien ci-dessus:

GET /object?apiKey=Qwerty2010

doivent être transmis comme tels:

GET /object?timestamp=1261496500&apiKey=Qwerty2010&signature=abcdef0123456789

La chaîne en cours de signature est /object?apikey=Qwerty2010&timestamp=1261496500et la signature est le hachage SHA256 de cette chaîne à l'aide du composant privé de la clé API.

La mise en cache des données côté serveur peut être toujours disponible. Par exemple, dans notre framework, nous mettons en cache les réponses au niveau SQL, pas au niveau URI. L'ajout de ce paramètre supplémentaire ne rompt donc pas le mécanisme de cache.

Consultez cet article pour plus de détails sur l'authentification RESTful dans notre infrastructure client-serveur ORM / SOA / MVC, basée sur JSON et REST. Étant donné que nous autorisons la communication non seulement via HTTP / 1.1, mais également les canaux nommés ou les messages GDI (localement), nous avons essayé d'implémenter un modèle d'authentification véritablement RESTful, et de ne pas compter sur la spécificité HTTP (comme l'en-tête ou les cookies).

Remarque ultérieure : l'ajout d'une signature dans l'URI peut être considéré comme une mauvaise pratique (car, par exemple, elle apparaîtra dans les journaux du serveur http), elle doit donc être atténuée, par exemple par un TTL approprié pour éviter les relectures. Mais si vos journaux http sont compromis, vous aurez certainement de plus gros problèmes de sécurité.

Dans la pratique, la prochaine authentification des jetons MAC pour OAuth 2.0 pourrait être une énorme amélioration par rapport au schéma actuel "Accordé par jeton". Mais c'est toujours un travail en cours et est lié à la transmission HTTP.

Conclusion

Il convient de conclure que REST n'est pas uniquement basé sur HTTP, même si, dans la pratique, il est également principalement implémenté sur HTTP. REST peut utiliser d'autres couches de communication. Ainsi, une authentification RESTful n'est pas seulement synonyme d'authentification HTTP, quelles que soient les réponses de Google. Il ne doit même pas utiliser du tout le mécanisme HTTP mais doit être abstrait de la couche de communication. Et si vous utilisez la communication HTTP, grâce à l' initiative Let's Encrypt, il n'y a aucune raison de ne pas utiliser le HTTPS approprié, qui est requis en plus de tout schéma d'authentification.


5
Si vous utilisez Cookieun meilleur remplacement, HTTP Basic Authvous pouvez effectuer une authentification sans état avec une méthode pour expirer l'authentification et la possibilité de vous déconnecter. Un exemple d'implémentation pourrait utiliser un cookie appelé Emulated-HTTP-Basic-Authavec une valeur similaire à l'authentification HTTP de base réelle et en plus définir un délai d'expiration. La déconnexion peut ensuite être mise en œuvre en supprimant ce cookie. Je suppose que tout client capable de prendre en charge l'authentification de base HTTP peut également prendre en charge l'authentification par cookie effectuée de cette manière.
Mikko Rantalainen

4
@MikkoRantalainen Mais ce cookie sera toujours géré par le serveur, comme je l'ai écrit. C'est une sorte d'apatride, mais pas un apatride "pur". Dans tous les cas, vous avez besoin d'un code JavaScript dédié à la connexion / déconnexion client, ce qui est parfaitement possible par exemple avec HTTP Digest Auth - bonne idée, mais pas de gros avantage, ici, pour réinventer la roue.
Arnaud Bouchez

4
Je dirais que le serveur implémente l'interface utilisateur et la logique pour configurer l'en-tête, mais l'en-tête lui-même est sans état. Un client conçu pour l'API peut ignorer l'aide du serveur pour configurer l'en-tête et simplement transmettre les informations requises similaires à HTTP Basic Auth. Mon point est que les UA communs (navigateurs) ont une implémentation de l'authentification de base si mauvaise qu'elle ne peut pas être utilisée. Une émulation fournie par le serveur pour les mêmes éléments dans un autre en-tête ( Cookie) peut être utilisée à la place.
Mikko Rantalainen

6
Je suppose que la bonne réponse est stackoverflow.com/questions/6068113/…
graffic

7
L'invite mot de passe pour l'autorisation HTTP n'apparaîtra que si le serveur le demande en renvoyant la réponse 401 non autorisée. Si vous ne l'aimez pas, envoyez simplement un 403 Forbidden à la place. La page d'erreur peut inclure une méthode de connexion ou un lien vers celle-ci. Cependant, mais le plus grand argument contre les cookies ET l'authentification http (indépendamment du fait que l'état soit côté serveur ou côté client) est qu'ils sont vulnérables à la falsification de requêtes intersites. Pour cette raison, la meilleure approche est un schéma d'autorisation personnalisé, un en-tête d'autorisation personnalisé ou un paramètre GET ou POST personnalisé.
Dobes Vandermeer

418

Je doute que les gens criant avec enthousiasme "Authentification HTTP" aient jamais essayé de créer une application basée sur un navigateur (au lieu d'un service Web de machine à machine) avec REST (aucune infraction prévue - je ne pense pas qu'ils aient jamais fait face aux complications) .

Les problèmes rencontrés avec l'utilisation de l'authentification HTTP sur les services RESTful qui produisent des pages HTML à afficher dans un navigateur sont les suivants:

  • l'utilisateur obtient généralement une boîte de connexion laid faite par navigateur, ce qui est très hostile à l'utilisateur. vous ne pouvez pas ajouter la récupération de mot de passe, des boîtes d'aide, etc.
  • la déconnexion ou la connexion sous un autre nom est un problème - les navigateurs continueront d'envoyer des informations d'authentification au site jusqu'à ce que vous fermiez la fenêtre
  • les délais d'attente sont difficiles

Un article très perspicace qui aborde ces points par point est ici , mais il en résulte beaucoup de piratage javascript spécifique au navigateur, des solutions de contournement pour les solutions de contournement, et cetera. En tant que tel, il n'est pas non plus compatible en amont et nécessitera donc une maintenance constante à mesure que de nouveaux navigateurs seront lancés. Je ne considère pas ce design épuré et clair, et je pense que c'est beaucoup de travail supplémentaire et de maux de tête juste pour pouvoir montrer avec enthousiasme mon badge REST à mes amis.

Je pense que les cookies sont la solution. Mais attendez, les cookies sont mauvais, non? Non, ils ne le sont pas, la façon dont les cookies sont souvent utilisés est mauvaise. Un cookie lui-même n'est qu'un élément d'information côté client, tout comme les informations d'authentification HTTP dont le navigateur garderait la trace pendant votre navigation. Et cette information côté client est envoyée au serveur à chaque demande, à nouveau comme le seraient les informations d'authentification HTTP. Sur le plan conceptuel, la seule différence est que le contenu de cet élément d'état côté client peut être déterminé par le serveur dans le cadre de sa réponse.

En faisant des sessions une ressource RESTful avec juste les règles suivantes:

  • Une session mappe une clé à un ID utilisateur (et éventuellement un horodatage de dernière action pour les délais d'expiration)
  • Si une session existe, cela signifie que la clé est valide.
  • Login signifie POSTing to / sessions, une nouvelle clé est définie comme cookie
  • La déconnexion signifie DELETEing / sessions / {key} (avec le POST surchargé, rappelez-vous, nous sommes un navigateur, et HTML 5 est encore loin)
  • L'authentification se fait en envoyant la clé sous forme de cookie à chaque demande et en vérifiant si la session existe et est valide

La seule différence avec l'authentification HTTP, maintenant, est que la clé d'authentification est générée par le serveur et envoyée au client qui continue de la renvoyer, au lieu que le client la calcule à partir des informations d'identification entrées.

converter42 ajoute que lors de l'utilisation de https (ce que nous devrions), il est important que le cookie ait son indicateur sécurisé défini afin que les informations d'authentification ne soient jamais envoyées via une connexion non sécurisée. Grand point, je ne l'avais pas vu moi-même.

Je pense que c'est une solution suffisante qui fonctionne bien, mais je dois admettre que je ne suis pas assez expert en sécurité pour identifier les trous potentiels dans ce schéma - tout ce que je sais, c'est que des centaines d'applications Web non RESTful utilisent essentiellement les mêmes protocole de connexion ($ _SESSION en PHP, HttpSession en Java EE, etc.). Le contenu de l'en-tête du cookie est simplement utilisé pour adresser une ressource côté serveur, tout comme une langue acceptée peut être utilisée pour accéder aux ressources de traduction, etc. Je sens que c'est pareil, mais peut-être que d'autres non? Que pensez-vous, les gars?


68
Il s'agit d'une réponse pragmatique et la solution proposée fonctionne. Cependant, utiliser les termes "RESTful" et "session" dans la même phrase est tout simplement faux (à moins qu'il n'y ait également "pas" entre les deux;). En d'autres termes: tout service Web qui utilise des sessions n'est PAS RESTful (par définition). Ne vous méprenez pas - vous pouvez toujours utiliser cette solution (YMMV), mais le terme "RESTful" ne peut pas être utilisé pour cela. Je recommande le livre O'Reilly sur REST qui est très lisible et explique le sujet en profondeur.
johndodo

23
@skrebbel: une solution REST pure enverrait des données d'authentification chaque fois qu'elle demande une ressource, ce qui n'est pas parfait (HTTP Auth le fait). La solution proposée fonctionne et est meilleure pour la plupart des cas d'utilisation, mais elle n'est pas RESTful. Pas besoin de guerre, j'utilise aussi cette solution. Je ne prétends pas que c'est reposant. :)
johndodo

94
Oh allez, donnez un exemple alors. Quelle est cette autre façon, qui fonctionne bien? J'aimerais vraiment savoir. L'authentification HTTP ne l'est certainement pas, vous ne pouvez pas vous déconnecter sans fermer le navigateur et vous ne pouvez pas offrir une UX de connexion décente sans beaucoup de JS spécifiques au navigateur, non compatibles avec l'avenir. Je ne me soucie pas tant de "purement RESTful" vs "presque RESTful" et de tout le débat religieux associé, mais si vous dites qu'il y a plusieurs façons, vous devriez les expliquer.
skrebbel

15
Une authentification véritablement RESTful avec des agents utilisateurs du monde réel (alias "navigateurs") consiste en un cookie contenant la valeur de l'authentification HTTP. De cette façon, le serveur peut fournir l'interface utilisateur pour entrer l'identifiant et le mot de passe et le serveur peut forcer la déconnexion (en supprimant le cookie). De plus, au lieu de répondre 401 pour exiger une connexion lorsque l'authentification échoue, le serveur doit utiliser une redirection temporaire vers l'écran de connexion et après une connexion réussie, utiliser une redirection temporaire vers l'emplacement précédent. De plus, le serveur doit intégrer une action de déconnexion (formulaire POST) à presque toutes les pages pour les utilisateurs connectés.
Mikko Rantalainen

15
Je ne vois rien de mal à utiliser "reposant" et "session" dans la même phrase tant qu'il est clair que la session n'existe que du côté client. Je ne sais pas pourquoi ce concept est si important.
Joe Phillips

140

On en dit déjà assez sur ce sujet par de bonnes personnes ici. Mais voici mes 2 cents.

Il existe 2 modes d'interaction:

  1. de l'homme à la machine (HTM)
  2. machine à machine (MTM)

La machine est le dénominateur commun, exprimé sous forme d'API REST, et les acteurs / clients étant soit les humains, soit les machines.

Maintenant, dans une architecture véritablement RESTful, le concept d'apatridie implique que tous les états d'application pertinents (c'est-à-dire les états côté client) doivent être fournis avec chaque demande. Par pertinent, cela signifie que tout ce qui est requis par l'API REST pour traiter la demande et servir une réponse appropriée.

Lorsque nous considérons cela dans le contexte des applications homme-machine, "basées sur un navigateur" comme le souligne Skrebbel ci-dessus, cela signifie que l'application (Web) exécutée dans le navigateur devra envoyer son état et les informations pertinentes à chaque demande. cela rend les API REST dorsales.

Considérez ceci: Vous disposez d'un atout exposé par la plateforme de données / informations des API REST. Vous disposez peut-être d'une plateforme de BI en libre-service qui gère tous les cubes de données. Mais vous voulez que vos clients (humains) y accèdent via (1) une application Web, (2) une application mobile et (3) une application tierce. En fin de compte, même une chaîne de MTM mène à HTM - à droite. Les utilisateurs humains restent donc au sommet de la chaîne d'information.

Dans les 2 premiers cas, vous avez un cas d'interaction homme-machine, les informations étant réellement consommées par un utilisateur humain. Dans le dernier cas, vous disposez d'un programme machine utilisant les API REST.

Le concept d'authentification s'applique à tous les niveaux. Comment allez-vous concevoir cela pour que vos API REST soient accessibles de manière uniforme et sécurisée? La façon dont je vois cela, il y a 2 façons:

Voie 1:

  1. Il n'y a pas de connexion, pour commencer. Chaque demande effectue la connexion
  2. Le client envoie ses paramètres d'identification + les paramètres spécifiques à la demande à chaque demande
  3. L'API REST les prend, se retourne, envoie un ping au magasin d'utilisateurs (quel qu'il soit) et confirme l'auth
  4. Si l'authentification est établie, traite la demande; sinon, refuse avec le code d'état HTTP approprié
  5. Répétez les étapes ci-dessus pour chaque demande de toutes les API REST de votre catalogue

Voie 2:

  1. Le client commence par une demande d'authentification
  2. Une API REST de connexion gérera toutes ces demandes
  3. Il prend les paramètres d'authentification (clé API, uid / pwd ou tout ce que vous choisissez) et vérifie l'authentification par rapport au magasin d'utilisateurs (LDAP, AD ou base de données MySQL, etc.)
  4. S'il est vérifié, crée un jeton d'authentification et le rend au client / appelant
  5. L'appelant envoie ensuite ce jeton d'authentification + les paramètres spécifiques de la demande avec chaque demande suivante à d'autres API REST d'entreprise, jusqu'à ce que vous soyez déconnecté ou jusqu'à l'expiration du bail

De toute évidence, dans Way-2, les API REST auront besoin d'un moyen de reconnaître et d'approuver le jeton comme valide. L'API de connexion a effectué la vérification d'authentification et, par conséquent, cette "clé de valet" doit être approuvée par d'autres API REST de votre catalogue.

Cela signifie bien sûr que la clé / le jeton d'authentification devra être stocké et partagé entre les API REST. Ce référentiel de jetons partagé et approuvé peut être local / fédéré, ce qui permet aux API REST d'autres organisations de se faire mutuellement confiance.

Mais je m'égare.

Le fait est qu'un "état" (concernant l'état authentifié du client) doit être maintenu et partagé afin que toutes les API REST puissent créer un cercle de confiance. Si nous ne le faisons pas, ce qui est la voie 1, nous devons accepter qu'un acte d'authentification doit être effectué pour toutes les demandes qui arrivent.

L'authentification est un processus gourmand en ressources. Imaginez exécuter des requêtes SQL, pour chaque demande entrante, sur votre magasin d'utilisateurs pour vérifier la correspondance uid / pwd. Ou, pour crypter et effectuer des correspondances de hachage (le style AWS). Et sur le plan architectural, chaque API REST devra effectuer cela, je suppose, en utilisant un service de connexion principal commun. Parce que, si vous ne le faites pas, vous jetez le code d'authentification partout. Un gros désordre.

Donc plus de couches, plus de latence.

Maintenant, prenez Way-1 et postulez à HTM. Votre utilisateur (humain) se soucie-t-il vraiment si vous devez envoyer uid / pwd / hash ou autre chose à chaque demande? Non, tant que vous ne la dérangez pas en lançant la page d'authentification / connexion à chaque seconde. Bonne chance d'avoir des clients si vous le faites. Donc, ce que vous allez faire est de stocker les informations de connexion quelque part côté client, dans le navigateur, dès le début, et de les envoyer avec chaque demande. Pour l'utilisateur (humain), elle s'est déjà connectée et une "session" est disponible. Mais en réalité, elle est authentifiée à chaque demande.

Même chose avec Way-2. Votre utilisateur (humain) ne le remarquera jamais. Aucun mal n'a donc été fait.

Et si nous appliquons Way-1 à MTM? Dans ce cas, puisque c'est une machine, nous pouvons supporter l'enfer de ce type en lui demandant de soumettre des informations d'authentification à chaque demande. Tout le monde s'en fout! L'exécution de Way-2 sur MTM ne provoquera aucune réaction particulière; c'est une putain de machine. Il s'en foutait moins!

Alors vraiment, la question est de savoir ce qui convient à votre besoin. L'apatridie a un prix à payer. Payez le prix et continuez. Si vous voulez être un puriste, alors payez le prix aussi et continuez.

En fin de compte, les philosophies n'ont pas d'importance. Ce qui compte vraiment, c'est la découverte, la présentation et l'expérience de consommation de l'information. Si les gens aiment vos API, vous avez fait votre travail.


3
Monsieur, vous l'avez si bien expliqué que j'ai une idée claire du problème / question de base à portée de main. Tu es comme le Bouddha! Puis-je ajouter qu'en utilisant HTTPS au niveau de la couche de transport, nous pouvons même empêcher les attaques de Man In the Middle, afin que personne ne détourne ma clé d'identification (si Way-1 est choisi)
Vishnoo Rath

N'est-ce pas toujours une machine qui fait l'authentification? L'humain ne se soucie pas des mots de passe, c'est une gêne regrettable pour les utilisateurs qui rationalisent correctement la sécurité. Pour moi, c'est un problème de développeur de savoir comment ils veulent que la machine fasse son travail.
Todd Baur

9
J'ai lu ta réponse; dans votre solution, pour chaque requête Web unique provenant du navigateur par les clics des utilisateurs, vous devrez renvoyer le "jeton d'authentification" à l'API que le clic de l'utilisateur appelle. Et alors? L'API effectue la vérification du jeton. Contre quoi? Contre une sorte de "magasin de jetons" qui maintient si ce jeton est valide ou non. N'êtes-vous pas d'accord pour dire que ce «magasin de jetons» devient alors le gardien de «l'État»? Vraiment, quelle que soit la façon dont vous voyez cela, quelqu'un quelque part doit savoir quelque chose sur les "jetons" transmis aux activités des utilisateurs. C'est là que vivent les informations de l'État.
Kingz

5
Et par service "sans état", ce que l'on veut vraiment dire, c'est que ce composant serveur particulier (les API CRUD) ne porte aucun état. Ils ne reconnaissent pas un utilisateur d'un autre et remplissent la demande de l'utilisateur dans son intégralité en une seule transaction. C'est l'apatridie. Mais quelqu'un quelque part doit être assis et juger si cet utilisateur est valide ou non. Il n'y a pas d'autre moyen de procéder; clés ou mots de passe ou autre chose. Tout ce qui est transmis du côté utilisateur doit être authentifié et autorisé.
Kingz

1
Vous manquez Way-3, l'approche hybride. Le client se connecte comme dans Way-2mais, comme dans Way-1, les informations d'identification ne sont vérifiées par rapport à aucun état côté serveur. Quoi qu'il en soit, un jeton d'authentification est créé et renvoyé au client comme dans Way-2. L'authenticité de ce jeton est vérifiée ultérieurement à l'aide d'une cryptographie asymétrique sans rechercher aucun état spécifique au client.
jcoffland

50

Voici une solution d'authentification véritablement et complètement RESTful:

  1. Créez une paire de clés publique / privée sur le serveur d'authentification.
  2. Distribuez la clé publique à tous les serveurs.
  3. Lorsqu'un client s'authentifie:

    3.1. émettez un jeton qui contient les éléments suivants:

    • Date d'expiration
    • nom d'utilisateur (facultatif)
    • IP des utilisateurs (facultatif)
    • hachage d'un mot de passe (facultatif)

    3.2. Chiffrez le jeton avec la clé privée.

    3.3. Renvoyez le jeton chiffré à l'utilisateur.

  4. Lorsque l'utilisateur accède à une API, il doit également transmettre son jeton d'authentification.

  5. Les serveurs peuvent vérifier que le jeton est valide en le déchiffrant à l'aide de la clé publique du serveur d'authentification.

Il s'agit d'une authentification sans état / RESTful.

Notez que si un hachage de mot de passe était inclus, l'utilisateur enverrait également le mot de passe non chiffré avec le jeton d'authentification. Le serveur a pu vérifier que le mot de passe correspondait au mot de passe utilisé pour créer le jeton d'authentification en comparant les hachages. Une connexion sécurisée utilisant quelque chose comme HTTPS serait nécessaire. Javascript côté client peut gérer l'obtention du mot de passe de l'utilisateur et son stockage côté client, soit en mémoire, soit dans un cookie, éventuellement chiffré avec la clé publique du serveur .


5
Que se passe-t-il si quelqu'un met la main sur ce jeton d'authentification et appelle des API avec lui en faisant semblant d'être client?
Abidi

2
@Abidi, oui c'est un problème. Vous pourriez avoir besoin d'un mot de passe. Un hachage du mot de passe peut être inclus dans le jeton d'authentification. Si quelqu'un était capable de voler le jeton, il serait vulnérable aux attaques par force brute hors ligne. Si une phrase de passe forte était choisie, ce ne serait pas un problème. Notez que si vous utilisez le vol de jeton https, l'attaquant devra d'abord accéder à la machine du client.
jcoffland

1
Parce que seul le serveur d'authentification connaît la clé privée. D'autres serveurs peuvent authentifier l'utilisateur en ne connaissant que la clé publique et le jeton de l'utilisateur.
jcoffland

1
Le chiffrement et le déchiffrement asymétriques sont un ordre de grandeur plus lents (plus gourmands en calcul) que le chiffrement symétrique.Avoir le serveur utilisant la clé publique pour déchiffrer le jeton à chaque appel serait un énorme goulot d'étranglement en termes de performances.
Craig

3
@jcoffland, vous avez vraiment promu votre réponse ici (à plusieurs reprises :-) Mais je ne peux m'empêcher de commenter les problèmes de performances (intensité de calcul) liés à l'utilisation du chiffrement asymétrique à chaque appel. Je ne vois tout simplement pas de solution capable de faire évoluer les choses. Recherchez HTTPS et le protocole SPDY. Il va très loin pour garder les connexions ouvertes (HTTP keep-alives, qui est l'état), et servir plusieurs ressources par lots sur la même connexion (plus d'état), et bien sûr SSL lui-même n'utilise que le chiffrement asymétrique pour échanger une clé de chiffrement symétrique ( indiquer également).
Craig

37

Pour être honnête avec vous, j'ai vu de grandes réponses ici, mais quelque chose qui me dérange un peu, c'est quand quelqu'un va pousser le concept de l'apatridie à l'extrême où il devient dogmatique. Cela me rappelle ces anciens fans de Smalltalk qui voulaient seulement adopter OO pur et si quelque chose n'est pas un objet, alors vous le faites mal. Laisse-moi tranquille.

L'approche RESTful est censée vous faciliter la vie et réduire les frais généraux et le coût des sessions, essayez de la suivre car c'est une chose sage à faire, mais la minute où vous suivez une discipline (n'importe quelle discipline / directive) à l'extrême où elle n'offre plus l'avantage auquel il était destiné, alors vous le faites mal. Certains des meilleurs langages d'aujourd'hui ont à la fois une programmation fonctionnelle et une orientation objet.

Si la façon la plus simple de résoudre votre problème est de stocker la clé d'authentification dans un cookie et de l'envoyer sur l'en-tête HTTP, faites-le, mais n'en abusez pas. N'oubliez pas que les sessions sont mauvaises lorsqu'elles deviennent lourdes et grandes, si toute votre session est constituée d'une courte chaîne contenant une clé, alors quel est le problème?

Je suis ouvert à accepter des corrections dans les commentaires, mais je ne vois pas l'intérêt (jusqu'à présent) de rendre nos vies misérables pour simplement éviter de garder un gros dictionnaire de hachages sur notre serveur.


2
Les gens n'essaient pas de vous interdire d'utiliser des sessions. Vous êtes libre de le faire. Mais si vous le faites, ce n'est pas REST.
André Caldas

6
@ AndréCaldas ce n'est pas REST de la même manière qu'avoir des fonctions ou des types primitifs dans une langue n'est pas du genre. Je ne dis pas qu'il est conseillé d'avoir des séances. Je donne simplement mon avis sur le fait de suivre un ensemble de pratiques dans la mesure où elles ne procurent plus d'avantages à quelqu'un. (Btw, remarquez que je ne m'oppose pas à vos remarques, cependant, je ne dirais pas que ce n'est pas du repos, je dirais que ce n'est pas du pur repos).
arg20

Alors, comment l'appelons-nous si ce n'est pas RESTful? Et sûrement, si une demande comprend l'ID de session, alors c'est aussi sans état qu'une demande incluant un ID utilisateur? Pourquoi les ID utilisateur sont-ils sans état et les ID session avec état?
mfhholmes

1
Les cookies sont vulnérables à la falsification de requêtes intersites, ils facilitent donc les violations de sécurité. Mieux vaut utiliser quelque chose qui n'est pas envoyé automatiquement par le navigateur, comme un en-tête personnalisé ou un schéma d'autorisation personnalisé.
Dobes Vandermeer

1
En fait, essayer d'être apatride ne relève pas du dogmatisme, mais d'une conception commune de la SOA elle-même. Les services devraient toujours bénéficier de leur découplage et de leur absence d'apatridie: en pratique, ils facilitent la mise à l'échelle, la disponibilité et la maintenabilité. Bien sûr, cela devrait être autant que possible, et vous auriez éventuellement besoin de certains "services d'orchestration" pour gérer ces services sans état dans une approche pragmatique dynamique.
Arnaud Bouchez

32

D'abord et avant tout, un service Web RESTful est STATELESS (ou en d'autres termes, SESSIONLESS). Par conséquent, un service RESTful n'a pas et ne devrait pas avoir de concept de session ou de cookies impliqué. La méthode d'authentification ou d'autorisation dans le service RESTful consiste à utiliser l'en-tête d'autorisation HTTP tel que défini dans les spécifications HTTP RFC 2616. Chaque demande unique doit contenir l'en-tête d'autorisation HTTP et la demande doit être envoyée via une connexion HTTP (SSL). C'est la bonne façon de procéder à l'authentification et de vérifier l'autorisation des demandes dans un service Web HTTP RESTful. J'ai implémenté un service Web RESTful pour l'application Cisco PRIME Performance Manager chez Cisco Systems. Et dans le cadre de ce service Web, j'ai également implémenté l'authentification / l'autorisation.


5
L'authentification HTTP nécessite toujours que le serveur garde une trace des identifiants et mots de passe des utilisateurs. Ce n'est pas complètement apatride.
jcoffland

21
Il est apatride dans le sens où chaque demande est valable seule sans aucune exigence des demandes précédentes. Comment cela est implémenté sur le serveur est une autre question, si l'authentification est coûteuse, vous pouvez faire un peu de mise en cache et vous authentifier à nouveau en cas d'échec du cache. Très peu de serveurs sont complètement sans état où la sortie est purement fonction de l'entrée. Il s'agit généralement d'une requête ou d'une mise à jour d'un état.
Erik Martino

3
Pas vrai. Dans ce cas, toutes vos demandes nécessitent un état d'une transaction précédente, à savoir l'enregistrement de l'utilisateur. Je ne vois pas pourquoi les gens continuent d'essayer de dire qu'un nom d'utilisateur et un mot de passe stockés sur le serveur ne sont pas un état côté serveur. Voir ma réponse.
jcoffland

1
@jcoffland En outre, votre solution repose largement sur la capacité du serveur API à déchiffrer le jeton signé. Je pense que cette approche est non seulement beaucoup trop spécifique, mais aussi un peu trop sophistiquée pour être considérée comme l'approche LA R. Fielding avait en tête de s'attaquer au problème de l'authentification RESTful.
Michael Ekoka

2
@jcoffland comprenez-vous à quel point le cryptage asymétrique est beaucoup plus gourmand en calcul (et donc gourmand en ressources et profondément lent)? Vous parlez d'un schéma qui utiliserait le chiffrement asymétrique sur chaque demande. L'aspect le plus lent du HTTPS, sans exception, est la prise de contact initiale qui implique la création de clés publiques / privées pour crypter asymétriquement un secret partagé qui est ensuite utilisé pour crypter symétriquement toutes les communications qui en découlent.
Craig

22

Il ne s'agit certainement pas de "clés de session" car elles sont généralement utilisées pour faire référence à une authentification sans session qui est effectuée dans toutes les contraintes de REST. Chaque demande est auto-descriptive et contient suffisamment d'informations pour autoriser la demande seule sans aucun état d'application côté serveur.

La façon la plus simple d'aborder cela est de commencer par les mécanismes d'authentification intégrés de HTTP dans RFC 2617 .


L'authentification HTTP nécessite que le serveur stocke le nom d'utilisateur et le mot de passe. Il s'agit d'un état côté serveur et donc pas strictement REST. Voir ma réponse.
jcoffland

3
@jcoffland: Ce n'est tout simplement pas vrai, sur les deux comptes. La première authentification HTTP ne nécessite pas du serveur de stocker le mot de passe. Le hachage du mot de passe est stocké à la place (bcrypt avec 8+ tours recommandé). Deuxièmement, le serveur n'a aucun état puisque l'en-tête d'autorisation est envoyé avec chaque demande. Et si vous considérez les hachages de mot de passe stockés comme un état , ils ne sont pas plus nombreux que les clés publiques stockées.
Boris B.

1
@Boris B., oui, je comprends que le mot de passe est stocké sous forme de hachage. Le mot de passe haché est toujours un état spécifique au client. La différence avec le stockage d'une clé publique, comme décrit dans ma solution, est qu'il n'y a qu'une seule clé publique, la clé publique du serveur d'authentification. C'est très différent de stocker un hachage de mot de passe par utilisateur. Peu importe comment vous l'habillez, si le serveur stocke un mot de passe pour chaque utilisateur, il est stocké par état utilisateur et n'est pas 100% REST.
jcoffland

7
Je ne pense pas que le stockage d'un mot de passe haché utilisateur sur le serveur doit être considéré comme un état côté serveur. Les utilisateurs sont des ressources contenant des informations telles que le nom, l'adresse ou le mot de passe haché.
Codepunkt

15

L'article «très perspicace» mentionné par @skrebel ( http://www.berenddeboer.net/rest/authentication.html ) traite d'une méthode d'authentification compliquée mais vraiment cassée.

Vous pouvez essayer de visiter la page (qui est censée être visible uniquement pour l'utilisateur authentifié) http://www.berenddeboer.net/rest/site/authenticated.html sans aucun identifiant de connexion.

(Désolé, je ne peux pas commenter la réponse.)

Je dirais que REST et l'authentification ne se mélangent tout simplement pas. REST signifie apatride mais «authentifié» est un état. Vous ne pouvez pas les avoir tous les deux sur le même calque. Si vous êtes un défenseur RESTful et froncez les sourcils sur les États, alors vous devez opter pour HTTPS (c'est-à-dire laisser le problème de sécurité à une autre couche).


Stripe.com dirait le contraire à votre commentaire sur REST et l'authentification ne se mélange pas ..
Erik

Apatride se réfère uniquement au serveur, pas au client. Le client peut se souvenir de tout l'état de la session et envoyer ce qui est pertinent à chaque demande.
Dobes Vandermeer

Enfin, quelqu'un parle d'un certain sens, mais l'authentification sans état est possible en utilisant la cryptographie à clé publique. Voir ma réponse.
jcoffland

1
Le serveur n'a pas d'état "authentifié". Il reçoit des informations via hypermédia et doit travailler avec lui pour retourner ce qui a été demandé. Rien de moins, rien de plus. Si la ressource est protégée et nécessite une authentification et une autorisation, l'hypermédia fourni doit inclure ces informations. Je ne sais pas d'où vient la notion selon laquelle l'authentification d'un utilisateur avant de renvoyer une ressource signifie que le serveur suit l'état. Fournir un nom d'utilisateur et un mot de passe peut très bien être considéré comme fournissant simplement plus de paramètres de filtrage.
Michael Ekoka

"Je dirais que REST et l'authentification ne font tout simplement pas bon ménage." Cela ressemble à du bon sens. Sauf qu'un système incompatible avec l'authentification ("authentifié" lui-même est, bien entendu, un état) est d'une utilité limitée. J'ai l'impression que nous discutons tous à l'intersection de l'aspect pratique et du dogmatisme puriste, et franchement, l'aspect pratique devrait gagner. Il existe de nombreux aspects de REST qui sont très bénéfiques sans entrer dans des contorsions en essayant d'éviter l'état en matière d'authentification, n'est-ce pas?
Craig

12

Je pense que l'authentification reposante implique le passage d'un jeton d'authentification comme paramètre dans la demande. Des exemples sont l'utilisation des apikeys par les api. Je ne pense pas que l'utilisation de cookies ou d'authentification http soit admissible.


Les cookies et l'authentification HTTP doivent être évités en raison de la vulnérabilité CSRF.
Dobes Vandermeer

@DobesVandermeer Pouvez-vous s'il vous plaît voir ma question si vous pouvez aider? stackoverflow.com/questions/60111743/…
Hemant Metalia

12

Mise à jour du 16 février 2019

L'approche mentionnée ci-dessous est essentiellement le type d'octroi "Resource Owner Password Credential" de OAuth2.0 . C'est un moyen facile de se mettre en marche. Cependant, avec cette approche, chaque application de l'organisation se retrouvera avec ses propres mécanismes d'authentification et d'autorisation. L'approche recommandée est le type de subvention "Code d'autorisation". De plus, dans ma réponse précédente ci-dessous, j'ai recommandé le navigateur localStorage pour stocker les jetons d'authentification. Cependant, j'en suis venu à croire que le cookie est la bonne option à cet effet. J'ai détaillé mes raisons, l'approche de mise en œuvre du type d'octroi de code d'autorisation, les considérations de sécurité, etc. dans cette réponse StackOverflow .


Je pense que l'approche suivante peut être utilisée pour l'authentification du service REST:

  1. Créez une API RESTful de connexion pour accepter le nom d'utilisateur et le mot de passe pour l'authentification. Utiliser la méthode HTTP POST pour empêcher la mise en cache et SSL pour la sécurité pendant le transit En cas d'authentification réussie, l'API renvoie deux JWT - un jeton d'accès (validité plus courte, disons 30 minutes) et un jeton d'actualisation (validité plus longue, disons 24 heures)
  2. Le client (une interface utilisateur basée sur le Web) stocke les JWT dans le stockage local et dans chaque appel d'API suivant passe le jeton d'accès dans l'en-tête "Authorization: Bearer #access token"
  3. L'API vérifie la validité du jeton en vérifiant la signature et la date d'expiration. Si le jeton est valide, vérifiez si l'utilisateur (il interprète la revendication "sub" dans JWT comme nom d'utilisateur) a accès à l'API avec une recherche de cache. Si l'utilisateur est autorisé à accéder à l'API, exécutez la logique métier
  4. Si le jeton a expiré, l'API renvoie le code de réponse HTTP 400
  5. Le client, lors de la réception de 400/401, appelle une autre API REST avec le jeton d'actualisation dans l'en-tête "Authorization: Bearer #refresh token" pour obtenir un nouveau jeton d'accès.
  6. Lors de la réception de l'appel avec le jeton d'actualisation, vérifiez si le jeton d'actualisation est valide en vérifiant la signature et la date d'expiration. Si le jeton d'actualisation est valide, actualisez le cache des droits d'accès de l'utilisateur à partir de la base de données et renvoyez le nouveau jeton d'accès et le jeton d'actualisation. Si le jeton d'actualisation n'est pas valide, retournez le code de réponse HTTP 400
  7. Si un nouveau jeton d'accès et un jeton d'actualisation sont renvoyés, passez à l'étape 2. Si le code de réponse HTTP 400 est renvoyé, le client suppose que le jeton d'actualisation a expiré et demande à l'utilisateur le nom d'utilisateur et le mot de passe.
  8. Pour vous déconnecter, purgez le stockage local

Avec cette approche, nous effectuons l'opération coûteuse de chargement du cache avec des détails de droits d'accès spécifiques à l'utilisateur toutes les 30 minutes. Donc, si un accès est révoqué ou qu'un nouvel accès est accordé, il faut 30 minutes pour réfléchir ou une déconnexion suivie d'une connexion.


alors l'utiliseriez-vous pour une API avec un site web statique fait avec angular par exemple? et qu'en est-il des applications mobiles?
Yazan Rawashdeh

8

C'est la façon de procéder: utiliser OAuth 2.0 pour la connexion .

Vous pouvez utiliser d'autres méthodes d'authentification que celle de Google tant qu'elle prend en charge OAuth.


1
OAuth2 n'est pas sécurisé sans HTTPS, ni sans état.
Arnaud Bouchez

4
Rien n'est sécurisé sans HTTPS.
Craig

1
@Craig et HTTPS peuvent ne pas être sécurisés non plus, si la chaîne de certificats est cassée, ce qui peut être pour de plus grands bien - en.wikipedia.org/wiki/Bullrun_(decryption_program) ;)
Arnaud Bouchez

1
@ArnaudBouchez Veuillez préciser en quoi le fait d'avoir une chaîne de certificats cassée est pour le plus grand bien? Je ne comprends pas où tu vas avec ça. ;)
Craig

@Craig Veuillez suivre le lien et profitez-en! Cette approche du «plus grand bien» était clairement cynique dans mon commentaire: les systèmes de type Bullrun sont destinés à «notre propre bien» par nos gouvernements bien-aimés et confiants.
Arnaud Bouchez

3

L'utilisation d'une infrastructure de clé publique dans laquelle l'enregistrement d'une clé implique une liaison appropriée garantit que la clé publique est liée à la personne à laquelle elle est affectée de manière à garantir la non-répudiation

Voir http://en.wikipedia.org/wiki/Public_key_infrastructure . Si vous suivez les normes PKI appropriées, la personne ou l'agent qui utilise incorrectement la clé volée peut être identifié et verrouillé. Si l'agent doit utiliser un certificat, la liaison devient assez serrée. Un voleur intelligent et rapide peut s'échapper, mais ils laissent plus de miettes.


2

Pour répondre à cette question de ma compréhension ...

Un système d'authentification qui utilise REST afin que vous n'ayez pas besoin de suivre ou de gérer réellement les utilisateurs de votre système. Cela se fait en utilisant les méthodes HTTP POST, GET, PUT, DELETE. Nous prenons ces 4 méthodes et les considérons en termes d'interaction avec la base de données comme CREATE, READ, UPDATE, DELETE (mais sur le Web, nous utilisons POST et GET car c'est ce que les balises d'ancrage prennent actuellement en charge). Ainsi, en traitant POST et GET comme notre CRÉER / LIRE / METTRE À JOUR / SUPPRIMER (CRUD), nous pouvons concevoir des itinéraires dans notre application Web qui seront en mesure de déduire quelle action de CRUD nous réalisons.

Par exemple, dans une application Ruby on Rails, nous pouvons créer notre application Web de telle sorte que si un utilisateur qui est connecté visite http://store.com/account/logout, le GET de cette page peut être vu comme l'utilisateur tentant de se déconnecter . Dans notre contrôleur de rails, nous construisons une action qui déconnecte l'utilisateur et le renvoie à la page d'accueil.

Un GET sur la page de connexion donnerait un formulaire. un POST sur la page de connexion serait considéré comme une tentative de connexion et prendrait les données POST et les utiliserait pour se connecter.

Pour moi, c'est une pratique d'utiliser des méthodes HTTP mappées à leur signification de base de données, puis de créer un système d'authentification en gardant à l'esprit que vous n'avez pas besoin de passer autour d'un identifiant de session ou de suivre des sessions.

J'apprends toujours - si vous trouvez quelque chose que j'ai dit de mal, corrigez-moi, et si vous en savez plus, postez-le ici. Merci.


2

Conseils valides pour sécuriser n'importe quelle application Web

Si vous souhaitez sécuriser votre application, vous devez certainement commencer par utiliser HTTPS au lieu de HTTP , cela garantit une création de canal sécurisé entre vous et les utilisateurs qui empêchera de renifler les données envoyées d'avant en arrière aux utilisateurs et aidera à conserver les données échangé confidentiel.

Vous pouvez utiliser des JWT (JSON Web Tokens) pour sécuriser les API RESTful , cela présente de nombreux avantages par rapport aux sessions côté serveur, les avantages sont principalement:

1- Plus évolutif, car vos serveurs API n'auront pas à maintenir de sessions pour chaque utilisateur (ce qui peut être un gros fardeau lorsque vous avez plusieurs sessions)

2- Les JWT sont autonomes et ont les revendications qui définissent le rôle d'utilisateur par exemple et ce à quoi il peut accéder et émis à la date et à la date d'expiration (après quoi le JWT ne sera pas valide)

3- Plus facile à gérer entre les équilibreurs de charge et si vous avez plusieurs serveurs API car vous n'aurez pas à partager les données de session ni à configurer le serveur pour acheminer la session vers le même serveur, chaque fois qu'une demande avec un JWT frappe n'importe quel serveur, elle peut être authentifiée & autorisé

4- Moins de pression sur votre base de données et vous n'aurez pas à stocker et récupérer en permanence l'identifiant et les données de session pour chaque demande

5- Les JWT ne peuvent pas être falsifiés si vous utilisez une clé forte pour signer le JWT, vous pouvez donc faire confiance aux réclamations dans le JWT envoyé avec la demande sans avoir à vérifier la session utilisateur et s'il est autorisé ou non , vous pouvez simplement vérifier le JWT et vous êtes prêt à savoir qui et ce que cet utilisateur peut faire.

De nombreuses bibliothèques offrent des moyens simples de créer et de valider des JWT dans la plupart des langages de programmation, par exemple: dans node.js, l'un des plus populaires est jsonwebtoken

Étant donné que les API REST visent généralement à garder le serveur sans état, les JWT sont plus compatibles avec ce concept car chaque demande est envoyée avec un jeton d'autorisation qui est autonome (JWT) sans que le serveur doive garder une trace de la session utilisateur par rapport aux sessions qui font le serveur avec état pour qu'il se souvienne de l'utilisateur et de son rôle, cependant, les sessions sont également largement utilisées et ont leurs avantages, que vous pouvez rechercher si vous le souhaitez.

Une chose importante à noter est que vous devez livrer le JWT en toute sécurité au client en utilisant HTTPS et l'enregistrer dans un endroit sûr (par exemple dans le stockage local).

Vous pouvez en savoir plus sur les JWT à partir de ce lien

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.