web-dev-qa-db-fra.com

Est-ce que les sessions violent vraiment le repos?

L'utilisation de sessions dans une API RESTful viole-t-elle vraiment RESTfulness? J'ai vu beaucoup d'opinions dans les deux sens, mais je ne suis pas convaincu que les sessions sont RESTless. De mon point de vue:

  • l'authentification n'est pas interdite pour RESTfulness (sinon, les services RESTful seraient peu utilisés)
  • l'authentification est effectuée en envoyant un jeton d'authentification dans la requête, généralement l'en-tête
  • ce jeton d'authentification doit être obtenu d'une manière ou d'une autre et peut être révoqué, auquel cas il doit être renouvelé
  • le jeton d'authentification doit être validé par le serveur (sinon ce ne serait pas une authentification)

Alors, comment les sessions violent-elles cela?

  • côté client, les sessions sont réalisées à l'aide de cookies
  • les cookies sont simplement un en-tête HTTP supplémentaire
  • un cookie de session peut être obtenu et révoqué à tout moment
  • les cookies de session peuvent avoir une durée de vie infinie si besoin est
  • l'identifiant de session (jeton d'authentification) est validé côté serveur

En tant que tel, pour le client, un cookie de session est exactement identique à tout autre mécanisme d'authentification basé sur un en-tête HTTP, à la différence qu'il utilise l'en-tête Cookie au lieu de Authorization ou un autre en-tête propriétaire. S'il n'y avait pas de session attachée à la valeur de cookie côté serveur, pourquoi cela ferait-il une différence? L'implémentation côté serveur n'a pas besoin de concerner le client aussi longtemps que le serveur se comporte RESTful. En tant que tels, les cookies en eux-mêmes ne doivent pas constituer une API RESTless, et les sessions sont simplement des cookies destinés au client.

Mes hypothèses sont-elles fausses? Qu'est-ce qui rend les cookies de session RESTless?

461
deceze

Premièrement, définissons quelques termes:

  • Reposant:

    On peut caractériser les applications conformes aux contraintes REST décrites dans cette section comme "RESTful". [15] Si un service enfreint l'une des contraintes requises, il ne peut pas être considéré comme RESTful.

    selon wikipedia .

  • contrainte sans état:

    Nous ajoutons ensuite une contrainte à l’interaction client-serveur: la communication doit être de nature non-statique, comme dans le style client-stateless-server (CSS) de la section 3.4.3 (Figure 5-3), de sorte que chaque requête du client à Le serveur doit contenir toutes les informations nécessaires à la compréhension de la demande et ne peut tirer parti d'aucun contexte stocké sur le serveur. L'état de la session est donc entièrement conservé sur le client.

    selon le mémoire de Fielding .

Les sessions côté serveur violent donc la contrainte sans état de REST, et donc RESTfulness non plus.

En tant que tel, pour le client, un cookie de session est exactement identique à tout autre mécanisme d'authentification basé sur un en-tête HTTP, à la différence qu'il utilise l'en-tête Cookie au lieu de l'autorisation ou d'un autre en-tête propriétaire.

Par les cookies de session, vous stockez l’état du client sur le serveur et votre demande a donc un contexte. Essayons d'ajouter un équilibreur de charge et une autre instance de service à votre système. Dans ce cas, vous devez partager les sessions entre les instances de service. Il est difficile de maintenir et d'étendre un tel système, il évolue donc mal ...

À mon avis, il n'y a rien de mal avec les cookies. La technologie des cookies est un mécanisme de stockage côté client dans lequel les données stockées sont automatiquement attachées aux en-têtes de cookie à chaque demande. Je ne connais pas de contrainte REST qui pose problème avec ce type de technologie. Il n'y a donc pas de problème avec la technologie elle-même, mais avec son utilisation. Fielding a écrit une sous-section pourquoi il pense que les cookies HTTP sont mauvais.

De mon point de vue:

  • l'authentification n'est pas interdite pour RESTfulness (sinon, les services RESTful seraient peu utilisés)
  • l'authentification est effectuée en envoyant un jeton d'authentification dans la requête, généralement l'en-tête
  • ce jeton d'authentification doit être obtenu d'une manière ou d'une autre et peut être révoqué, auquel cas il doit être renouvelé
  • le jeton d'authentification doit être validé par le serveur (sinon ce ne serait pas une authentification)

Votre point de vue était plutôt solide. Le seul problème concernait le concept de création d'un jeton d'authentification sur le serveur. Vous n'avez pas besoin de cette partie. Ce dont vous avez besoin est de stocker le nom d'utilisateur et le mot de passe sur le client et de les envoyer à chaque demande. Pour ce faire, vous n'avez pas besoin d'autre chose que l'authentification de base HTTP et une connexion chiffrée:

Figure 1. - Stateless authentication by trusted clients

  • Figure 1. - Authentification sans état par des clients de confiance

Vous avez probablement besoin d'un cache d'authentification en mémoire côté serveur pour accélérer les choses, car vous devez authentifier chaque requête.

Maintenant, cela fonctionne plutôt bien avec des clients de confiance écrits par vous, mais qu'en est-il des clients tiers? Ils ne peuvent pas avoir le nom d'utilisateur et mot de passe et toutes les autorisations des utilisateurs. Vous devez donc stocker séparément les autorisations qu'un client tiers peut avoir par un utilisateur spécifique. Les développeurs de clients peuvent donc enregistrer leurs clients tiers, obtenir une clé API unique et permettre aux utilisateurs d'autoriser les clients tiers à accéder à une partie de leurs autorisations. Par exemple, lisez le nom et l'adresse électronique, ou répertoriez leurs amis, etc. Après avoir autorisé un client tiers, le serveur génère un jeton d'accès. Ces jetons d'accès peuvent être utilisés par le client tiers pour accéder aux autorisations accordées par l'utilisateur, comme suit:

Figure 2. - Stateless authentication by 3rd party clients

  • Figure 2. - Authentification sans état par des clients tiers

Ainsi, le client tiers peut obtenir le jeton d'accès d'un client de confiance (ou directement de l'utilisateur). Après cela, il peut envoyer une requête valide avec la clé API et le jeton d'accès. C'est le mécanisme d'authentification par tierce partie le plus élémentaire. Vous pouvez en savoir plus sur les détails de la mise en œuvre dans la documentation de chaque système d'authentification tiers, par exemple. OAuth. Bien sûr, cela peut être plus complexe et plus sécurisé, par exemple, vous pouvez signer les détails de chaque requête côté serveur et envoyer la signature avec la requête, etc. La solution dépend des besoins de votre application.

283
inf3rno

Tout d’abord, REST n’est pas une religion et ne devrait pas être abordé en tant que tel. Bien que les services RESTful présentent des avantages, vous ne devez suivre les principes de REST que dans la mesure où ils ont un sens pour votre application.

Cela dit, l’authentification et l’état côté client ne violent pas les principes REST. Bien que REST nécessite que les transitions d'état soient sans état, cela fait référence au serveur lui-même. Au coeur, tout le REST concerne les documents. L'idée derrière l'apatridie est que le serveur est apatride, pas les clients. Tout client émettant une demande identique (mêmes en-têtes, mêmes cookies, URI, etc.) doit être placé au même endroit dans l'application. Si le site Web stockait l'emplacement actuel de l'utilisateur et gérait la navigation en mettant à jour cette variable de navigation côté serveur, il serait alors violé REST. Un autre client avec des informations de requête identiques serait transféré vers un emplacement différent en fonction de l'état côté serveur.

Les services Web de Google sont un exemple fantastique de système RESTful. Ils exigent un en-tête d'authentification avec la clé d'authentification de l'utilisateur à transmettre à chaque demande. Cela enfreint légèrement les principes REST, car le serveur suit l'état de la clé d'authentification. L'état de cette clé doit être conservé et il comporte une sorte de date/heure d'expiration après laquelle elle n'accorde plus l'accès. Cependant, comme je l’ai mentionné en haut de mon message, des sacrifices doivent être consentis pour permettre à une application de fonctionner réellement. Cela dit, les jetons d'authentification doivent être stockés de manière à permettre à tous les clients possibles de continuer à octroyer l'accès pendant leurs heures de validité. Si un serveur gère l'état de la clé d'authentification au point qu'un autre serveur avec équilibrage de charge ne peut pas exécuter les requêtes en fonction de cette clé, vous avez déjà commencé à violer les principes de REST. Les services de Google garantissent qu'à tout moment, vous pouvez utiliser le jeton d'authentification que vous utilisiez sur votre téléphone contre le serveur d'équilibrage de charge et accéder au serveur d'équilibrage de charge B depuis votre bureau tout en continuant d'accéder au système et d'être redirigé vers les mêmes ressources si les demandes étaient identiques.

En résumé, vous devez vous assurer que vos jetons d’authentification sont validés par rapport à un magasin de sauvegarde quelconque (base de données, cache, etc.) pour que vous conserviez autant de propriétés REST que possible.

J'espère que tout cela a du sens. Vous devriez également consulter le section Contraintes du article de wikipedia sur le transfert d'état représentatif si vous ne l'avez pas déjà fait. C’est particulièrement éclairant en ce qui concerne ce que les principes de REST plaident réellement et pourquoi.

326
Jared Harding

Les cookies ne sont pas destinés à l'authentification. Pourquoi réinventer une roue? HTTP a des mécanismes d'authentification bien conçus. Si nous utilisons des cookies, nous n'utilisons HTTP que comme protocole de transport. Nous devons donc créer notre système de signalisation propre, par exemple, pour indiquer aux utilisateurs qu'ils ont mal fourni l'authentification (avec HTTP 401, par exemple). incorrect car nous ne fournirions probablement pas Www-Authenticate à un client, car les spécifications HTTP exigent :)). Il convient également de noter que Set-Cookie n'est qu'une recommandation pour le client. Son contenu peut être ou ne pas être enregistré (par exemple, si les cookies sont désactivés), tandis que l'en-tête Authorization est envoyé automatiquement à chaque demande.

Un autre point est que, pour obtenir un cookie d'autorisation, vous voudrez probablement fournir vos informations d'identification quelque part en premier? Si oui, alors ce ne serait-il pas sans repos? Exemple simple:

  • Vous essayez GET /a sans cookie
  • Vous obtenez une demande d'autorisation en quelque sorte
  • Vous allez et autorisez en quelque sorte comme POST /auth
  • Vous obtenez Set-Cookie
  • Vous essayez GET /aavec cookie. Mais GET /a se comporte-t-il de manière indifférente dans ce cas?

Pour résumer, je pense que si nous avons accès à une ressource et que nous devons nous authentifier, nous devons nous authentifier sur cette même ressource, pas ailleurs.

12
starteleport

En réalité, RESTfulness s'applique uniquement à RESOURCES, comme indiqué par un identificateur de ressource universel. Donc, même parler de choses comme les en-têtes, les cookies, etc. en ce qui concerne REST n'est pas vraiment approprié. REST peut fonctionner avec n'importe quel protocole, même si cela se fait de manière routinière via HTTP.

Le déterminant principal est le suivant: si vous envoyez un appel REST, qui est un URI, une fois que l'appel est passé avec succès au serveur, cet URI renvoie-t-il le même contenu, en supposant qu'aucune transition n'a été effectuée ( PUT, POST, DELETE)? Ce test exclut les erreurs ou les demandes d'authentification renvoyées car, dans ce cas, la demande n'a pas encore été transmise au serveur, c'est-à-dire le servlet ou l'application qui renverra le document correspondant à l'URI donné.

De même, dans le cas d'un POST ou d'un PUT, pouvez-vous envoyer un URI/charge utile donné, et quel que soit le nombre de fois que vous envoyez le message, les données seront toujours mises à jour, de sorte que les GET suivants seront automatiquement mis à jour renvoyer un résultat cohérent?

REST concerne les données de l'application et non les informations de bas niveau nécessaires pour transférer ces données.

Dans le billet de blog suivant, Roy Fielding a donné un bon résumé de l’ensemble de REST idée:

http://groups.yahoo.com/neo/groups/rest-discuss/conversations/topics/5841

"Un système RESTful passe d'un état stable à un autre, et chaque état stable est un état de départ potentiel et un état final potentiel. Par exemple, un système RESTful est un nombre inconnu de composants obéissant à un ensemble simple de règles telles qu'elles sont toujours soit à REST, soit en passant d'un état RESTful à un autre état RESTful. Chaque état peut être parfaitement compris par la ou les représentations qu'il contient et par l'ensemble des transitions qu'il fournit, avec le système peut être un diagramme d'états complexe, mais chaque agent d'utilisateur ne peut voir qu'un état à la fois (l'état d'équilibre actuel) et est donc simple et peut être analysé indépendamment. Un utilisateur, OTOH, peut créer ses propres transitions à tout moment (par exemple, entrer une URL, sélectionner un signet, ouvrir un éditeur, etc.). "


S'agissant de la question de l'authentification, qu'elle soit réalisée via des cookies ou des en-têtes, tant que les informations ne font pas partie de l'URI et de la charge POST, cela n'a vraiment rien à voir avec REST du tout. Donc, en ce qui concerne le fait d'être sans état, nous ne parlons que des données d'application.

Par exemple, lorsque l'utilisateur saisit des données dans un écran graphique, le client garde trace des champs saisis, des champs non remplis, des champs obligatoires manquants, etc. Ceci est tout CLIENT CONTEXT, et ne doit pas être envoyé ni suivi. par le serveur. Ce qui est envoyé au serveur, c'est l'ensemble complet des champs qui doivent être modifiés dans la ressource IDENTIFIED (par l'URI), de sorte qu'une transition se produit dans cette ressource d'un état RESTful à un autre.

Ainsi, le client garde une trace de ce que l'utilisateur fait et envoie uniquement des transitions d'état complètes et logiques au serveur.

7
Ken Kopelson

La transaction HTTP, authentification d'accès de base, ne convient pas à RBAC, car l'authentification d'accès de base utilise le nom d'utilisateur crypté: mot de passe chaque fois pour l'identifier, alors que ce qui est nécessaire dans RBAC est le rôle que l'utilisateur souhaite utiliser pour un appel spécifique. RBAC ne valide pas les autorisations sur le nom d'utilisateur, mais sur les rôles.

Vous pouvez tricasser pour concaténer comme ceci: usernameRole: mot de passe, mais c'est une mauvaise pratique, et c'est aussi inefficace car lorsqu'un utilisateur a plus de rôles, le moteur d'authentification doit tester tous les rôles en concaténation et chaque appel à nouveau. Cela détruirait l'un des plus importants avantages techniques de RBAC, à savoir un test d'autorisation très rapide.

Ce problème ne peut donc pas être résolu à l'aide de l'authentification d'accès de base.

Pour résoudre ce problème, le maintien de session est nécessaire, et cela semble, selon certaines réponses, en contradiction avec REST.

C’est ce qui me plaît dans la réponse selon laquelle REST ne devrait pas être traité comme une religion. Dans les analyses de rentabilisation complexes, dans les soins de santé, par exemple, le RBAC est absolument commun et nécessaire. Et il serait dommage qu’ils ne soient pas autorisés à utiliser REST, car tous les concepteurs d’outils REST traiteraient REST comme une religion.

Pour moi, il n'y a pas beaucoup de façons de maintenir une session sur HTTP. On peut utiliser des cookies, avec un ID de session, ou un en-tête avec un ID de session.

Si quelqu'un a une autre idée, je serai heureux de l'entendre.

1
Bert Verhees