web-dev-qa-db-fra.com

Authentification pour REST services Web

Je commence à concevoir un service Web REST et je ne connais pas bien la meilleure approche en matière d'authentification. Le service permettra aux utilisateurs individuels d’accéder à leurs propres données et de les gérer; un type d’authentification de l’utilisateur est donc nécessaire. J'ai examiné ces options:

  • OAuth

OAuth semble porter davantage sur l'autorisation que sur l'authentification. Je prévois de gérer les autorisations de manière native au sein des services, je ne cherche donc pas de solution à ce problème. Mais, OAuth est-il également approprié pour l'authentification?

  • OpenID

OpenID fournit certes une solution pour l’authentification, mais elle vise davantage à permettre aux utilisateurs d’utiliser leurs informations d’identité tierces (Google, Yahoo, etc.). Bien que je veuille soutenir cela, ce n’est pas une préoccupation majeure pour moi, et je le ferai. permettre définitivement aux utilisateurs de s'inscrire avec des informations d'identification natives (email/mot de passe).

  • Authentification HTTP Basic

C’est simple à mettre en œuvre, mais je crois comprendre que cette méthode n’est peut-être pas très sûre. En outre, il semblerait que l'échange d'informations d'identification soit nécessaire pour chaque accès, mais je préférerais que l'utilisateur s'authentifie une fois puis poursuive l'accès via un jeton de session.

  • Authentification personnalisée

Fondamentalement, lancez mon propre service de génération de login/token et demandez un token valide pour accéder à toutes les autres ressources (évidemment, tout se ferait via SSL).


En plus de créer les services Web, je vais également créer une application client (Web) qui utilise ces services pour le compte d'un utilisateur, mais je ne souhaite pas que l'application doive stocker des informations/des informations d'identification d'utilisateur, etc. Donc, quelque chose comme ça:

Utilisateur (authentifié avec un e-mail/mot de passe ou des informations d'identification de tiers) -> Application Web (authentifiée avec l'ID de l'application) -> services Web

Et encore une fois, je veux permettre aux autres de créer des clients également, afin que le niveau intermédiaire puisse être n'importe quelle application tierce:

Utilisateur (authentifié avec un e-mail/mot de passe ou des informations d'identification de tiers) -> Application tierce (authentifiée avec l'ID de l'application) -> services Web

Mes exigences de très haut niveau sont:

  • Sécurisé (évidemment)
  • Identifiants natifs
  • Prise en charge des informations d'identification de tiers (Google, Yahoo, LinkedIn, etc.)
  • Prise en charge de plusieurs clients (application Web, application mobile, applications tierces, etc.)
  • Informations d'identification du client (juste un identifiant d'application?)
  • Sessions de connexion qui expirent
  • L'autorisation n'est pas requise 

Ma question est donc, basée sur ce qui précède (s'il vous plaît laissez-moi savoir si cela est trop vague), existe-t-il une "meilleure" approche? Est-ce que OAuth ou OpenID est approprié, ou est-ce que je complique trop la procédure, et devrais-je simplement lancer ma propre authentification?

MODIFIER:

Je pense que je devrai mettre en œuvre ce qui suit: 

1) Identifiants/jetons natifs (authentification de base HTTP sur SSL?) 

2) Une "partie de confiance" OpenID pour permettre à mon API d'utiliser des OpenID hébergés ailleurs (c'est-à-dire "prise en charge des informations d'identification de tiers")

3) Un "consommateur" OAuth pour autoriser mon API à accéder à des services tiers (par exemple, accéder au profil LinkedIn d'un utilisateur). 

4) Un "fournisseur" OpenID pour permettre aux utilisateurs d'utiliser les identifiants natifs de l'API ailleurs (facultatif) 

5) Un "fournisseur" OAuth pour permettre aux applications tierces d'accéder à mon API au nom de l'utilisateur (facultatif) 

Cela vous semble-t-il correct ou est-ce que je complique davantage la tâche?

42
user2943799

Vous pouvez envisager JWT (jeton Web JSON), voir JWT draft rfc . Cela répondrait certainement à vos exigences en matière de sécurité et d'expiration de session. Cependant, étant donné qu’il s’agit d’un projet de norme, il est peu probable qu’il soit utilisé couramment à l’heure actuelle, cela pourrait changer rapidement puisque JWT fait partie d’OAuth 2.0. JWT est facile à implémenter dans la plupart des langues et il existe déjà de nombreuses bibliothèques. En guise d'explication simple, un jeton JWT se compose de 3 parties: l'en-tête, le corps et la signature. L'en-tête et le corps sont des objets json codés en basee64url (les alphabets diffèrent de base64 par les 2 derniers caractères), puis signés avec HMAC256 (ou un autre algorithme spécifié dans l'en-tête). Le RFC explique comment générer exactement cette signature. Vous voudrez peut-être vérifier ceci générateur de jetons en ligne .

JWT sont des en-têtes http et des paramètres de requête conviviaux.

12
nullptr

Une des bonnes options à considérer est «Authentification par clé partagée». Il s'agit du type d'authentification utilisé par le service Web Amazon et le service de stockage Windows Azure. Nous avons utilisé l'authentification par clé partagée dans le service REST que nous avons développé. Vous pouvez effectuer une recherche rapide dans Google pour "Authentification par clé partagée". Vous obtiendrez de nombreux détails. 

J'ai écrit un article de blog ici à ce sujet.

Les étapes de haut niveau sont:

  1. Le client combine un ensemble de données uniques (éléments) définies par le service REST.
  2. Signer ces données combinées à l'aide d'une clé uniquement connue du client et du service REST
  3. Envoyez cette signature au service REST en tant que valeur pour l'en-tête HTTP
  4. Le service REST calcule la signature exactement de la même manière que le client
  5. Compare la signature envoyée par le client avec celle calculée, si celle-ci suppose une requête valide, sinon refuse la requête
11
Anu Thomas Chandy

Ma suggestion est d'authentifier la première demande, puis de configurer un jeton de session.

L'application frontale stockerait le jeton et le fournirait avec chaque demande ultérieure.

Le jeton aurait un délai d'expiration. Le jeton expirera s'il n'est pas utilisé pendant une certaine période.

Le jeton peut être associé à l'adresse IP d'origine pour plus de sécurité.

Le jeton peut être transmis en tant que cookie ou en tant que paramètre de requête dans une URL.

Si le problème de l'authentification du client SSL est acceptable, vous pouvez utiliser une authentification SSL mutuelle. Chaque client devrait être doté d'un certificat approuvé par le serveur. Il peut s'agir du même certificat, ou de certificats différents si vous devez traiter les clients différemment.

7
ArunasR

En fonction de vos besoins, je pense que OAuth 2.0 pourrait en fait être une option intéressante. OAuth est bien un protocole d'autorisation, mais c'est aussi Authenticates le client avec clientId et clientSecret. Vous pouvez utiliser le Client Credential Flow et choisir de ne pas inclure un Refresh Token, de cette manière, l'utilisateur dispose d'un Access Token, qui expire après un certain temps. Et comme OAuth est un protocole largement utilisé, il existe déjà de nombreuses bibliothèques client et côté serveur que vous et vos clients pouvez utiliser.

Si vous pensez que OAuth est trop lourd ou trop compliqué pour votre application, je resterais probablement avec Basic Authentication sur HTTPS. Mais comme je l'ai également dit dans une autre réponse à une question similaire, je n'inventerais jamais mon propre mécanisme d'authentification.

Pour plus d’informations, vous pouvez également consulter l’autre réponse que j’avais donnée précédemment à une question similaire: https://stackoverflow.com/a/15003777/849741

2
Jos Vinke

Vous pouvez utiliser HTTP Basic Auth, où le mot de passe transféré n’est pas réellement un mot de passe, mais un jeton, que le client a acquis sur une demande de ressource différente, où il/elle a dû fournir son mot de passe une fois et une seule fois ( peut-être même sur un autre canal). Cela ne sécurise pas les attaques d'interception (car il n'y a pas de signature de message), mais vous pouvez toujours demander au client de générer un jeton dynamique (c'est-à-dire sur un service d'authentification de votre choix), puis faites-le envoyer ce jeton en remplacement du mot de passe, de sorte que le mot de passe actuel ne soit pas constamment transféré par fil ..__ Oui, cela apparaît comme l'une des "solutions d'authentification personnalisées", mais ce n'est pas en réalité parce que vous pouvez imposer quoi N'oubliez jamais les règles que vous souhaitez sur le mot de passe de jeton, comme l'utilisation d'un jeton de signature comme mot de passe lié à la session ou recalculé à chaque demande (sans partage de secrets) afin que le serveur puisse valider le message, quels que soient vos besoins. L'idée est d'envoyer le jeton de validation en tant que "mot de passe" de la demande HTTP Basic Auth et de ne pas s'appuyer sur des protocoles plus compliqués, sans exclure ceux-ci (à votre choix).

1
Kai

J'ai implémenté et publié en open source un service de base qui permet l'authentification, il peut facilement être modifié pour permettre la connexion à 3 tuples si nécessaire. Il a environ 2 ans et est écrit en Java au printemps. Vous voudrez peut-être reconsidérer la technologie, mais cela fonctionne et vous pouvez vous faire une idée de base de la procédure. Trouvez-le ici sur google , ou suivez mes articles de blog à ce sujet. Notez que l'application ne se charge plus sur cloudbees, mais que tout se passe bien sur votre compte.

1
TheZuck

Je suggère d'utiliser Spring Boot pour vos services Web RESTful car vous pouvez ensuite utiliser Spring Security pour implémenter votre propre authentification personnalisée en fonction de leurs modèles. Vous pouvez implémenter votre propre authentification personnalisée en développant ou en implémentant respectivement leurs classes de sécurité de base et leurs interfaces. Vous avez également la possibilité d’incorporer les autres mécanismes d’authentification que vous avez énumérés dans Spring Boot si nécessaire.

0
Ramil