web-dev-qa-db-fra.com

REST Autorisation et authentification API (web + mobile)

J'ai lu sur oAuth, Amazon REST, HTTP Basic/Digest et ainsi de suite, mais je ne peux pas tout mettre en "pièce unique". C'est probablement la situation la plus proche - Création d'une API pour les applications mobiles - Authentification et autorisation

Je voudrais créer un site Web axé sur l'API - service. Donc (au début) j'aurais une API au centre et site web (PHP + MySQL) se connecterait via cURL, Android et iPhone via leurs interfaces réseau. Donc 3 clients principaux - 3 clés API. Et tout autre développeur pourrait également développer via l'interface API et ils obtiendraient leur propre clé API. Les actions de l'API seraient acceptées/rejetées en fonction de l'état de UserLevel, si je suis administrateur, je peux supprimer quoi que ce soit, etc., tous les autres ne peuvent manipuler que leurs données locales (compte).

Tout d'abord, l'autorisation - dois-je utiliser oAuth + xAuth ou ma mise en œuvre en quelque sorte (voir http://docs.amazonwebservices.com/AmazonCloudFront/latest) /DeveloperGuide/RESTAuthentication.html?r=9197 )? Si je comprends bien, sur l'utilisateur du service Amazon est == utilisateur API (possède la clé API). Sur mon service, je dois séparer les utilisateurs/comptes standard (celui qui s'est inscrit sur le site Web) et les comptes de développeur (qui devraient avoir leur clé API).

Il me faudrait donc tout d'abord autoriser la clé API puis Authentifier l'utilisateur lui-même. Si j'utilise le schéma d'Amazon pour vérifier les clés API du développeur (autoriser leur application), quel schéma dois-je utiliser pour l'authentification des utilisateurs?

J'ai lu comment obtenir un jeton via api.example.org/auth après (via [~ # ~] https [~ # ~], HTTP Basic) après avoir affiché mon nom d'utilisateur et mon mot de passe, puis les transmettre à chaque demande suivante. Comment gérer les jetons si je suis connecté simultanément sur Android et un site web? Qu'en est-il de l'attaque de l'homme du milieu si j'utilise SSL uniquement à la première demande (lorsque le nom d'utilisateur et le mot de passe sont transmis) et juste HTTP les uns sur les autres? N'est-ce pas un problème dans cet exemple Mot de passe protégeant un service REST?

69
svenkapudija

Comme toujours, la meilleure façon de protéger une clé n'est pas de la transmettre.

Cela dit, nous utilisons généralement un schéma dans lequel chaque "clé API" comprend deux parties: un ID non secret (par exemple 1234) et une clé secrète (par exemple octet [64]).

  • Si vous donnez une clé API, stockez-la (salée et hachée) dans la base de données de votre service.
  • Si vous donnez des comptes d'utilisateurs (protégés par mot de passe), stockez les mots de passe (salés et hachés) dans la base de données de votre service

Maintenant, quand un consommateur premier accède à votre API, pour se connecter, demandez-lui

  • Envoyer un paramètre "nom d'utilisateur" ("john.doe" n'est pas secret)
  • Envoyer un paramètre "APIkeyID" ("1234", pas secret)

et lui rendre

  • les sels de votre base de données (Dans le cas où l'un des paramètres est erroné, restituez simplement du sel répétable - par exemple. sha1 (nom d'utilisateur + "notverysecret").
  • L'horodatage du serveur

Le consommateur doit stocker le sel pendant la durée de la session pour garder les choses rapides et fluides, et il doit calculer et conserver le décalage de temps entre le client et le serveur.

Le consommateur doit maintenant calculer les hachages salés de la clé API et du mot de passe. De cette façon, le consommateur a exactement les mêmes hachages pour le mot de passe et la clé API, que ce qui est stocké dans votre base de données, mais sans que rien ne soit jamais passé par le fil.

Maintenant, quand un consommateur par la suite accède à votre API, pour faire du vrai travail, demandez-lui

  • Envoyer un paramètre "nom d'utilisateur" ("john.doe" n'est pas secret)
  • Envoyer un paramètre "APIkeyID" ("1234", pas secret)
  • Envoyer un paramètre "RequestSalt" (octet [64], aléatoire, non secret)
  • Envoyer un paramètre "RequestTimestamp" (calculé à partir de l'heure du client et du décalage connu)
  • Envoyer un paramètre "RequestToken" (hachage (passwordhash + request_salt + request_timestamp + apikeyhash))

Le serveur ne doit pas accepter les horodatages de plus de 2 secondes dans le passé, pour le sécuriser contre une attaque de relecture.

Le serveur peut désormais calculer le même hachage (passwordhash + request_salt + request_timestamp + apikeyhash) que le client, et assurez-vous que

  • le client connaît la clé API,
  • le client connaît le mot de passe correct
123
Eugen Rieck