web-dev-qa-db-fra.com

Service Web RESTful - Comment authentifier les demandes d'autres services?

Je conçois un service Web RESTful auquel les utilisateurs, mais également d'autres services Web et applications, doit accéder. Toutes les demandes entrantes doivent être authentifiées. Toutes les communications se font via HTTPS. L’authentification de l’utilisateur va se baser sur un jeton d’authentification, acquis en postant le nom d’utilisateur et le mot de passe (via une connexion SSL) à une ressource /session fournie par le service.

Dans le cas des clients de service Web, il y a pas d'utilisateur final derrière le service client. Les demandes sont lancées par des tâches planifiées. , événements ou autres opérations informatiques. La liste des services de connexion est connue à l’avance (évidemment, je suppose). Comment devrais-je authentifier ces requêtes provenant d'autres services (Web)? Je veux que le processus d'authentification soit aussi simple que possible à mettre en œuvre pour ces services, mais pas au détriment de la sécurité. Quelles seraient les normes et les meilleures pratiques pour un scénario comme celui-ci?

Options que je peux penser (ou qui m’ont été suggérées):

  1. Demandez aux services client de disposer d'un "faux" nom d'utilisateur et mot de passe, et de les authentifier de la même manière que les utilisateurs. Je n'aime pas cette option - ça ne me semble pas juste.

  2. Attribuez un identifiant d'application permanent au service client, éventuellement une clé d'application. Autant que je sache, cela revient à avoir un nom d’utilisateur + un mot de passe. Avec cet identifiant et cette clé, je peux authentifier chaque demande ou créer un jeton d'authentification pour authentifier les autres requêtes. Quoi qu’il en soit, cette option ne me plaît pas, car toute personne pouvant obtenir l’identifiant et la clé de l’application peut emprunter l’identité du client.

  3. Je pourrais ajouter une vérification d'adresse IP à l'option précédente. Cela rendrait plus difficile l'exécution de fausses demandes.

  4. Certificats clients. Configurer ma propre autorité de certification, créer un certificat racine et créer des certificats client pour les services client. Quelques problèmes me viennent toutefois à l’esprit: a) comment permettre aux utilisateurs de s’authentifier sans certificat et b) quelle complexité ce scénario met-il en œuvre du point de vue du service client?

  5. Autre chose - il doit y avoir d'autres solutions?

Mon service fonctionnerait sur Java, mais j'ai délibérément omis de préciser le cadre sur lequel il serait construit, car je suis davantage intéressé par les principes de base que par les détails de la mise en œuvre. Je suppose que la meilleure solution à cet égard être possible de mettre en œuvre quel que soit le cadre sous-jacent. Cependant, comme je suis un peu inexpérimenté sur ce sujet, des conseils et des exemples concrets sur la mise en œuvre effective (tels que des bibliothèques tierces utiles, des articles, etc.) seront également très appréciés.

113
Tommi

Toute solution à ce problème se résume à un secret partagé. Je n'aime pas non plus l'option nom d'utilisateur et mot de passe codée en dur, mais elle a l'avantage d'être assez simple. Le certificat client est également bon mais est-ce vraiment très différent? Il y a un certificat sur le serveur et un sur le client. Son principal avantage est qu’il est plus difficile de recourir à la force brutale. Espérons que vous ayez d'autres protections en place pour vous protéger contre cela.

Je ne pense pas que votre argument A pour la solution de certificat client soit difficile à résoudre. Vous utilisez simplement une branche. if (client side certificat) { check it } else { http basic auth } Je ne suis pas Java et je n'ai jamais travaillé avec celui-ci pour créer des certificats côté client. Cependant, un rapide Google nous amène à ce tutoriel qui regarde droit dans votre allée.

En dépit de toutes ces discussions sur le "meilleur", permettez-moi de souligner qu'il existe une autre philosophie qui dit: "moins de code, moins d'intelligence, c'est mieux". (Je tiens personnellement cette philosophie). La solution de certificat client ressemble à beaucoup de code.

Je sais que vous avez posé des questions sur OAuth, mais la proposition OAuth2 inclut une solution à votre problème appelée " jetons de support ", qui doit être utilisée conjointement avec SSL. Je pense que, par souci de simplicité, je choisirais soit un utilisateur/passe codé en dur (un par application pour pouvoir les révoquer individuellement), soit des jetons de support très similaires.

33
newz2000

Après avoir lu votre question, je dirais, générez un jeton spécial pour faire la demande requise. Ce jeton vivra dans le temps spécifique (disons dans une journée).

Voici un exemple pour générer un jeton d'authentification:

(day * 10) + (month * 100) + (year (last 2 digits) * 1000)

par exemple: 3 juin 2011

(3 * 10) + (6 * 100) + (11 * 1000) = 
30 + 600 + 11000 = 11630

puis concaténer avec le mot de passe de l'utilisateur, exemple "my4wesomeP4ssword!"

11630my4wesomeP4ssword!

Puis faites MD5 de cette chaîne:

05a9d022d621b64096160683f3afe804

Quand appelez-vous une demande, utilisez toujours ce jeton,

https://mywebservice.com/?token=05a9d022d621b64096160683f3afe804&op=getdata

Ce jeton est toujours unique chaque jour, alors je suppose que ce type de protection est plus que suffisant pour toujours protéger votre service.

L'espoir aide

:)

35
kororo

Il existe plusieurs approches possibles.

  1. Les puristes RESTful voudront que vous utilisiez l'authentification BASIC et que vous envoyiez les informations d'identification à chaque demande. Leur raison est que personne ne stocke aucun état.

  2. Le service client peut stocker un cookie, qui conserve un identifiant de session. Personnellement, je ne trouve pas cela aussi offensant que certains des puristes dont je parle - il peut être coûteux de s'authentifier encore et encore. On dirait que vous n'aimez pas trop cette idée, cependant.

  3. D'après votre description, il semble que vous soyez peut-être intéressé par OAuth2 D'après mon expérience, d'après ce que j'ai vu, c'est un peu déroutant et un peu saignant. Il existe des implémentations, mais elles sont rares. En Java, je crois comprendre qu’il a été intégré aux modules sécurité de Spring3. (Leur tutoriel est bien écrit.) J'attendais de voir s'il y aurait une extension dans Restlet , mais jusqu'à présent, même si cela a été proposé et peut-être dans l'incubateur, il n'a toujours pas été complètement intégré.

11
jwismar

5. Quelque chose d'autre - il doit y avoir d'autres solutions?

Vous avez raison, il y a! Et cela s'appelle JWT (JSON Web Tokens).

JSON Web Token (JWT) est un standard ouvert (RFC 7519) qui définit un moyen compact et autonome de transmettre des informations en toute sécurité entre les parties sous forme d'objet JSON. Ces informations peuvent être vérifiées et approuvées car elles sont signées numériquement. Les JWT peuvent être signés à l'aide d'un secret (avec l'algorithme HMAC) ou d'une paire de clés publique/privée à l'aide de RSA.

Je recommande fortement de regarder dans JWTs. Ils constituent une solution beaucoup plus simple au problème par rapport aux solutions alternatives.

https://jwt.io/introduction/

3
justin.hughey

En ce qui concerne l'approche du certificat client, il ne serait pas très difficile à mettre en œuvre tout en permettant aux utilisateurs ne disposant pas de certificat client d'entrer.

Si vous avez effectivement créé votre propre autorité de certification auto-signée et émis des certs client pour chaque service client, vous disposez d'un moyen simple d'authentifier ces services.

Selon le serveur Web que vous utilisez, il devrait exister une méthode pour spécifier une authentification client qui acceptera un certificat client, mais n'en nécessitera pas. Par exemple, dans Tomcat lors de la spécification de votre connecteur https, vous pouvez définir "clientAuth = vouloir" au lieu de "true" ou "false". Assurez-vous ensuite d’ajouter votre certificat d’auto-signature auto-signé à votre fichier de clés certifiées (par défaut, le fichier cacerts du JRE que vous utilisez, sauf si vous spécifiez un autre fichier dans la configuration de votre serveur Web), afin que les seuls certificats sécurisés soient ceux émis par votre auto-signée CA.

Côté serveur, vous autoriserez uniquement l’accès aux services que vous souhaitez protéger si vous êtes en mesure de récupérer un certificat client à partir de la demande (et non null), et transmet les contrôles de nom distinctif si vous préférez une sécurité supplémentaire. Pour les utilisateurs sans certificats client, ils pourront toujours accéder à vos services, mais n'auront tout simplement aucun certificat dans la demande.

À mon avis, c’est la méthode la plus "sûre", mais elle a certainement sa courbe d’apprentissage et ses frais généraux; elle ne constitue donc pas nécessairement la meilleure solution pour vos besoins.

3
bobz32

Je crois que l'approche:

  1. Première demande, le client envoie son identifiant/mot de passe
  2. Exchange id/pass pour jeton unique
  3. Valider le jeton à chaque demande ultérieure jusqu'à son expiration

est assez standard, quelle que soit la manière dont vous implémentez et d’autres détails techniques spécifiques.

Si vous voulez vraiment pousser l'enveloppe, vous pouvez peut-être considérer la clé https du client dans un état temporairement non valide jusqu'à la validation des informations d'identification, limiter les informations si elles ne le sont jamais et accorder l'accès lorsqu'elles sont validées, à nouveau à l'expiration.

J'espère que cela t'aides

3
Dynrepsys

Vous pouvez créer une session sur le serveur et partager sessionId entre le client et le serveur avec chaque appel REST.

  1. Première authentification REST request: /authenticate. Retourne la réponse (selon le format de votre client) avec sessionId: ABCDXXXXXXXXXXXXXX;

  2. Stockez ce sessionId dans Map avec la session réelle. Map.put(sessionid, session) ou utilisez SessionListener pour créer et détruire des clés pour vous;

    public void sessionCreated(HttpSessionEvent arg0) {
      // add session to a static Map 
    }
    
    public void sessionDestroyed(HttpSessionEvent arg0) {
      // Remove session from static map
    }
    
  3. Obtenez une sessionid avec chaque appel REST, comme URL?jsessionid=ABCDXXXXXXXXXXXXXX (Ou tout autre moyen);

  4. Retrive HttpSession de la carte en utilisant sessionId;
  5. Valider la demande pour cette session si la session est active;
  6. Envoyer une réponse ou un message d'erreur.
1
arviarya

J'utiliserais une application pour rediriger un utilisateur vers votre site avec un paramètre d'identifiant d'application, une fois que l'utilisateur a approuvé la demande, générer un jeton unique utilisé par l'autre application pour l'authentification. De cette manière, les autres applications ne gèrent pas les informations d'identification de l'utilisateur et d'autres applications peuvent être ajoutées, supprimées et gérées par les utilisateurs. Foursquare et quelques autres sites s’authentifient de cette manière et il est très facile à implémenter comme l’autre application.

0
Devin M