web-dev-qa-db-fra.com

REST et variantes d'authentification

Je travaille actuellement sur une bibliothèque REST pour .net, et j'aimerais entendre quelques opinions sur un point ouvert que j'ai: REST et l'authentification.

Voici un exemple d'une interface RESTful utilisée avec la bibliothèque:

[RestRoot("/user")]
public interface IUserInterface
{
  [RestPut("/")]
  void Add(User user);

  [RestGet("/")]
  int[] List();

  [RestGet("/get/{id}")]
  User Get(int id);

  [RestDelete("/delete/{id}")]
  void Delete(int id);
}

Le code serveur implémente alors simplement l'interface et les clients peuvent obtenir la même interface via une usine. Ou si le client n'utilise pas la bibliothèque, une requête HTTP standard fonctionne également.

Je sais qu'il existe les principaux moyens d'utiliser HTTP Basic Auth ou d'envoyer un jeton aux demandes nécessitant des utilisateurs authentifiés.

La première méthode (HTTP Basic Auth) présente les problèmes suivants (en partie spécifiques au navigateur Web):

  • Le mot de passe est transmis à chaque demande - même avec SSL, cela a une sorte de "mauvaise impression".
  • Étant donné que le mot de passe est transmis avec un en-tête de demande, il serait facile pour un attaquant local de regarder les en-têtes transmis pour obtenir le mot de passe.
  • Le mot de passe est disponible dans la mémoire du navigateur.
  • Aucun moyen standard pour expirer les "sessions" utilisateur.
  • La connexion avec un navigateur interrompt l'apparence d'une page.

Les problèmes de la deuxième méthode sont plus centrés sur l'implémentation et l'utilisation de la bibliothèque:

  • Chaque URI de demande qui nécessite une authentification doit avoir un paramètre pour le jeton, qui est juste très répétitif.
  • Il y a beaucoup plus de code à écrire si chaque implémentation de méthode doit vérifier si un jeton est valide.
  • L'interface deviendra moins spécifique, par exemple [RestGet("/get/{id}")] vs [RestGet("/get/{id}/{token}")].
  • Où mettre le jeton: à la fin de l'URI? après la racine? ailleurs?

Mon idée était de passer le jeton comme paramètre à l'URL comme http:/server/user/get/1234?token=token_id.

Une autre possibilité serait d'envoyer le paramètre en tant qu'en-tête HTTP, mais cela compliquerait l'utilisation avec des clients HTTP simples, je suppose.

Le jeton serait retransmis au client sous la forme d'un en-tête HTTP personnalisé ("X-Session-Id") à chaque demande.

Cela pourrait alors être complètement abstrait de l'interface, et toute implémentation nécessitant une authentification pourrait simplement demander à quel utilisateur le jeton (s'il est donné) appartient.

Pensez-vous que cela violerait trop REST ou avez-vous de meilleures idées?

69
Fionn

J'ai tendance à croire que les détails d'authentification appartiennent à l'en-tête, pas à l'URI. Si vous comptez sur un jeton placé sur l'URI, chaque URI de votre application devra être codé pour inclure le jeton. Cela aurait également un impact négatif sur la mise en cache. Les ressources dont le jeton est en constante évolution ne pourront plus être mises en cache. Les informations relatives aux ressources appartiennent à l'URI, et non aux données liées aux applications telles que les informations d'identification.

Il semble que vous deviez cibler les navigateurs Web en tant que client? Si c'est le cas, vous pouvez étudier l'utilisation de authentification d'accès HTTP Digest ou émettre aux clients leurs propres certificats SSL pour les identifier et les authentifier de manière unique. De plus, je ne pense pas que les cookies de session soient nécessairement une mauvaise chose. Surtout lorsque vous devez gérer un navigateur. Tant que vous isolez le code de gestion des cookies et que vous ne comptez pas sur le reste de l'application, tout ira bien. La clé est seulement de stocker l'identité de l'utilisateur dans la session, rien d'autre. N'abusez pas de l'état de session côté serveur.

Si vous ciblez des clients autres que le navigateur, vous pouvez adopter un certain nombre d'approches. J'ai eu de la chance avec l'utilisation du mécanisme Authentification S d'Amazon.

Tout cela est bien sûr très subjectif. Pureté et suivi REST à la lettre peut parfois ne pas être pratique. Tant que vous minimisez et isolez un tel comportement, le cœur de votre application peut toujours être RESTful. Je recommande fortement RESTful Web Services comme une excellente source d'informations et d'approches REST.

64
laz

Je suis d'accord avec workmad3, si la durée de vie de la session doit être maintenue, vous devez créer une ressource de session. La publication sur cette ressource avec les informations d'identification de l'utilisateur (authentification de base ou informations d'identification dans le contenu du corps) renverra un identifiant de session unique. Supprimer sur/session/{id} déconnectera l'utilisateur.

Si vous souhaitez contrôler l'heure d'expiration de la session. Lors de la création d'une nouvelle session (publication sur la ressource de session), le serveur définira un cookie sur la réponse (en utilisant l'en-tête set-cookie standard). Le cookie contiendra une date d'expiration. La chaîne de cookie doit être cryptée sur le serveur, de sorte que seul le serveur peut ouvrir ce cookie. Chaque demande conséquente au serveur enverra le cookie de session dans l'en-tête du cookie. (cela se fera automatiquement pour vous si votre client est un navigateur). Le serveur doit "renouveler" le cookie pour chaque demande, c'est-à-dire créer un nouveau cookie avec une nouvelle heure d'expiration (prolonger le délai d'expiration de la session). N'oubliez pas d'effacer le cookie lorsque l'utilisateur appelle delete sur la ressource de session.

Si vous souhaitez que votre application soit plus sécurisée, vous pouvez stocker l'adresse IP du client dans le cookie lui-même, donc lorsqu'une demande arrive, le serveur peut valider qu'elle a été envoyée par le client "d'origine". Mais rappelez-vous que cette solution peut être problématique lorsque des mandataires sont impliqués, car le serveur peut "voir" toutes les demandes comme provenant du même client.

15
LiorH

L'authentification restante que j'ai vue traite les sessions comme une ressource REST pour la création, la destruction, etc., puis l'ID de session est transmis de part et d'autre. Celles que j'ai vues ont tendance à utiliser le cookie de session pour cela car c'est le seul moyen de le sécuriser vraiment. Si vous passez l'identifiant de session dans l'URL, vous n'avez aucun moyen de vraiment l'authentifier auprès du bon client.

L'authentification est un problème délicat avec REST cependant, car elle nécessite qu'une certaine forme d'état soit conservée en dehors de l'URL, ce qui enfreint REST les principes de l'URL étant tous qui est nécessaire pour représenter l'État.

4
workmad3