Création d'une API pour les applications mobiles - Authentification et autorisation

189

Aperçu

Je cherche à créer une API (REST) ​​pour mon application. L'objectif initial / principal sera la consommation par les applications mobiles (iPhone, Android, Symbian, etc.). J'ai étudié différents mécanismes d'authentification et d'autorisation pour les API Web (en étudiant d'autres implémentations). J'ai la tête tournée vers la plupart des concepts fondamentaux mais je suis toujours à la recherche de conseils dans quelques domaines. La dernière chose que je veux faire est de réinventer la roue, mais je ne trouve aucune solution standard qui corresponde à mes critères (cependant mes critères peuvent être erronés, alors n'hésitez pas à critiquer cela aussi). De plus, je souhaite que l'API soit la même pour toutes les plates-formes / applications qui la consomment.

oAuth

Je vais aller de l'avant et rejeter mon objection à oAuth car je sais que ce sera probablement la première solution proposée. Pour les applications mobiles (ou plus spécifiquement les applications non Web), il semble tout simplement erroné de quitter l'application (pour accéder à un navigateur Web) pour l'authentification. De plus, il n'y a aucun moyen (à ma connaissance) pour le navigateur de renvoyer le rappel à l'application (en particulier multiplateforme). Je connais quelques applications qui font cela, mais cela ne semble pas juste et donne une pause dans l'application UX.

Exigences

  1. L'utilisateur entre le nom d'utilisateur / mot de passe dans l'application.
  2. Chaque appel d'API est identifié par l'application appelante.
  3. Les frais généraux sont réduits au minimum et l'aspect authentification est intuitif pour les développeurs.
  4. Le mécanisme est sécurisé tant pour l'utilisateur final (ses informations de connexion ne sont pas exposées) que pour le développeur (leurs informations d'identification d'application ne sont pas exposées).
  5. Si possible, ne pas exiger https (en aucun cas une exigence stricte).

Mes réflexions actuelles sur la mise en œuvre

Un développeur externe demandera un compte API. Ils recevront un apikey et un apisecret. Chaque demande nécessitera au moins trois paramètres.

  • apikey - remis au développeur lors de l'enregistrement
  • horodatage - sert également d'identifiant unique pour chaque message pour un apikey donné
  • hash - un hachage de l'horodatage + l'apisecret

L'apikey est nécessaire pour identifier l'application émettrice de la demande. L'horodatage agit de la même manière que oauth_nonce et évite / atténue les attaques de relecture. Le hachage garantit que la demande a effectivement été émise par le propriétaire de l'apikey donné.

Pour les demandes authentifiées (celles effectuées pour le compte d'un utilisateur), je suis toujours indécis entre une route access_token ou un combo de hachage nom d'utilisateur et mot de passe. Quoi qu'il en soit, à un moment donné, un combo nom d'utilisateur / mot de passe sera requis. Donc, quand c'est le cas, un hachage de plusieurs informations (apikey, apisecret, horodatage) + le mot de passe serait utilisé. J'aimerais avoir des commentaires sur cet aspect. FYI, ils devraient d'abord hacher le mot de passe, car je ne stocke pas les mots de passe dans mon système sans hachage.

Conclusion

Pour info, il ne s'agit pas d'une demande sur la façon de créer / structurer l'API en général, mais uniquement sur la façon de gérer l'authentification et l'autorisation à partir uniquement d'une application.

Pensées aléatoires / questions bonus

Pour les API qui ne nécessitent qu'un apikey dans le cadre de la demande, comment empêcher quelqu'un d'autre que le propriétaire de l'apikey de pouvoir voir l'apikey (depuis envoyé en clair) et faire des demandes excessives pour les pousser au-delà des limites d'utilisation? Peut-être que je réfléchis juste à cela, mais ne devrait-il pas y avoir quelque chose pour authentifier qu'une demande a été vérifiée auprès du propriétaire de l'apikey? Dans mon cas, c'était le but de l'apisecret, il n'est jamais montré / transmis sans être haché.

En parlant de hachage, qu'en est-il de md5 vs hmac-sha1? Est-ce vraiment important que toutes les valeurs soient hachées avec des données suffisamment longues (c.-à-d. Apisecret)?

J'avais déjà envisagé d'ajouter un sel par utilisateur / ligne au hachage de mot de passe de mes utilisateurs. Si je devais faire cela, comment l'application pourrait-elle créer un hachage correspondant sans connaître le sel utilisé?

jsuggs
la source
1
J'espérais recevoir quelques commentaires / suggestions supplémentaires. La question est-elle trop vague / ambiguë?
jsuggs
6
la question est parfaite mais, même presque 2 ans plus tard, les implémentations oauth semblent être des arcanes ... j'ai le plus de mal à réaliser exactement ce dont vous avez discuté ci-dessus. j'ai une dimension supplémentaire: je ne veux pas utiliser une paire loginName / password - je veux utiliser la vérification d'identité google sur android / ios (symbian a été déclaré par le WWF une "espèce presque disparue") et je refuse de développer pour Windows mobile (peu importe comment ils l'appellent ces jours-ci).
tony gil
8
c'est ridicule que, autant que tout le monde suggère oauth 2.0, je n'ai pas encore trouvé un tutoriel clair et simple ou un exemple qui utilise l'anglais commun pour expliquer les étapes, les exigences, les choses à faire et à ne pas faire ect ....
ChuckKelly
2
Lisez ce flux spécifique d'OAuth2.0 (le flux de mot de passe du propriétaire de la ressource). Pas de redirection vers le site Web. techblog.hybris.com/2012/06/11/…
Franklin
1
Je cherche également la même réponse. J'ai trouvé un bon article qui a été écrit récemment. J'espère que ça aide. stormpath.com/blog/the-ultimate-guide-to-mobile-api-security
Nouveau sur Rails

Réponses:

44

La façon dont je pense faire la partie connexion de ceci dans mes projets est:

  1. avant de se connecter, l'utilisateur demande un login_tokenau serveur. Ceux-ci sont générés et stockés sur le serveur sur demande, et ont probablement une durée de vie limitée.

  2. pour se connecter, l'application calcule le hachage du mot de passe de l'utilisateur, puis hache le mot de passe avec le login_tokenpour obtenir une valeur, puis renvoie à la fois le login_tokenhachage et le hachage combiné.

  3. Le serveur vérifie login_tokencelui qu'il a généré, le supprimant de sa liste de login_tokens valides . Le serveur combine ensuite son hachage stocké du mot de passe de l'utilisateur avec le login_tokenet s'assure qu'il correspond au jeton combiné soumis. Si cela correspond, vous avez authentifié votre utilisateur.

Les avantages de ceci sont que vous ne stockez jamais le mot de passe de l'utilisateur sur le serveur, le mot de passe n'est jamais passé en clair, le hachage du mot de passe n'est transmis qu'en clair lors de la création du compte (bien qu'il puisse y avoir des moyens de contourner cela), et cela devrait être à l'abri des attaques de relecture car le login_tokenest supprimé de la base de données lors de l'utilisation.

Michael Anderson
la source
Merci, j'ai oublié d'ajouter la partie sur le hachage du mot de passe côté application. Je ne stocke pas les mots de passe de mes utilisateurs en clair (je hache avant de stocker).
jsuggs
2
Je vois un inconvénient de cette méthode: vous ne pouvez pas stocker de mots de passe salés dans DB. Si des attaquants mettent la main sur votre base de données, ils n'auront pas besoin de déchiffrer. Puisque le hachage de mot de passe est le vrai mot de passe dans ce schéma.
sigod
2
@sigod Vous avez raison. Bien que je pense qu'il y a là une dichotomie fondamentale - vous devez soit faire confiance à votre transport, soit faire confiance à votre stockage. Les systèmes de connexion qui utilisent des mots de passe salés font confiance à la couche de transport - et transmettent ainsi le mot de passe de l'utilisateur au système d'authentification en clair. Ce cas ne fait pas confiance à la couche de transport (je pense que c'était parce que la plate-forme que je ciblais avait un mauvais support pour SHTTP). Si vous faites confiance à la couche de transport, vous pourrez peut-être faire d'autres compromis.
Michael Anderson
J'ai 3 problèmes: 1) comment le mot de passe de l'utilisateur n'est-il jamais stocké sur le serveur? à l'étape 2, vous avez mentionné qu'il stockait le mot de passe de l'utilisateur haché. 2) Le mot de passe utilisateur n'est jamais transmis en clair. Mais il est en fait haché sur le client, puis comparé au mot de passe haché sur le serveur, ce qui revient presque à le transmettre et à le stocker en clair, à quoi ça sert? 3) Cette méthode suppose que l'attaquant ne sait pas comment login_token + password est haché, ce qui viole le principe de Kerckhoffs et le rend vraiment non sécurisé.
Tamer Shlash
14

C'est tout un tas de questions en une, je suppose que pas mal de gens n'ont pas réussi à les lire jusqu'au bout :)

Mon expérience de l'authentification de service Web est que les gens la surengine généralement, et les problèmes ne sont que les mêmes que ceux que vous rencontriez sur une page Web. Les options très simples possibles incluraient https pour l'étape de connexion, retourner un jeton, exiger qu'il soit inclus avec les demandes futures. Vous pouvez également utiliser l'authentification de base http, et simplement passer des éléments dans l'en-tête. Pour plus de sécurité, faites régulièrement pivoter / expirez les jetons, vérifiez que les demandes proviennent du même bloc IP (cela peut devenir compliqué lorsque les utilisateurs mobiles se déplacent entre les cellules), combinez-les avec une clé API ou similaire. Sinon, effectuez l'étape «demande de clé» de oauth (quelqu'un l'a déjà suggéré dans une réponse précédente et c'est une bonne idée) avant d'authentifier l'utilisateur, et utilisez-la comme clé requise pour générer le jeton d'accès.

Une alternative que je n'ai pas encore utilisée mais dont j'ai beaucoup entendu parler comme une alternative conviviale à oAuth est xAuth . Jetez-y un coup d'œil et si vous l'utilisez, je serais vraiment intéressé de savoir quelles sont vos impressions.

Pour le hachage, sha1 est un peu meilleur, mais ne vous en faites pas - tout ce que les périphériques peuvent facilement (et rapidement dans un sens des performances) implémenter est probablement bien.

J'espère que cela aide, bonne chance :)

Lorna Mitchell
la source
Merci pour la réponse. J'ai étudié xAuth et cela pourrait être la voie à suivre pour pouvoir me retrouver avec une installation oAuth, ce qui en fait un processus plus standardisé pour interagir avec l'API.
jsuggs
9

Vous recherchez donc une sorte de mécanisme d'authentification côté serveur qui gérera les aspects d'authentification et d'autorisation d'une application mobile?

En supposant que c'est le cas, je l'aborderais comme suit (mais seulement parce que je suis un développeur Java, donc un gars C # le ferait différemment):

Le service d'authentification et d'autorisation RESTful

  1. Cela ne fonctionnera que sur HTTPS pour éviter les écoutes clandestines.
  2. Il sera basé sur une combinaison de RESTEasy , Spring Security et CAS (pour une connexion unique sur plusieurs applications).
  3. Il fonctionnera avec les navigateurs et les applications clientes Web
  4. Il y aura une interface de gestion de compte basée sur le Web pour permettre aux utilisateurs de modifier leurs détails, et les administrateurs (pour des applications particulières) pour modifier les niveaux d'autorisation

La bibliothèque / application de sécurité côté client

  1. Pour chaque plate-forme prise en charge (par exemple Symbian, Android, iOS, etc.), créez une implémentation appropriée de la bibliothèque de sécurité dans le langage natif de la plate-forme (par exemple Java, ObjectiveC, C, etc.)
  2. La bibliothèque doit gérer la formation de la requête HTTPS en utilisant les API disponibles pour la plate-forme donnée (par exemple, Java utilise URLConnection, etc.)
  3. Les utilisateurs de la bibliothèque générale d'authentification et d'autorisation («cos c'est tout ce que c'est) coderont sur une interface spécifique et ne seront pas heureux si elle change un jour, alors assurez-vous qu'elle est très flexible. Suivez les choix de conception existants tels que Spring Security.

Alors maintenant que la vue de 30 000 pieds est complète, comment procédez-vous? Eh bien, il n'est pas si difficile de créer un système d'authentification et d'autorisation basé sur les technologies répertoriées côté serveur avec un client navigateur. En combinaison avec HTTPS, les frameworks fourniront un processus sécurisé basé sur un jeton partagé (généralement présenté comme un cookie) généré par le processus d'authentification et utilisé chaque fois que l'utilisateur souhaite faire quelque chose. Ce jeton est présenté par le client au serveur à chaque fois qu'une demande a lieu.

Dans le cas de l'application mobile locale, il semble que vous recherchiez une solution qui effectue les opérations suivantes:

  1. L'application cliente a une liste de contrôle d'accès (ACL) définie contrôlant l'accès d'exécution aux appels de méthode. Par exemple, un utilisateur donné peut lire une collection à partir d'une méthode, mais son ACL autorise uniquement l'accès aux objets qui ont un Q dans leur nom, de sorte que certaines données de la collection sont extraites de manière silencieuse par l'intercepteur de sécurité. En Java, c'est simple, il vous suffit d'utiliser les annotations Spring Security sur le code d'appel et d'implémenter un processus de réponse ACL approprié. Dans d'autres langues, vous êtes seul et vous devrez probablement fournir un code de sécurité standard qui appelle votre bibliothèque de sécurité. Si le langage prend en charge AOP (Aspect Oriented Programming), utilisez-le au maximum pour cette situation.
  2. La bibliothèque de sécurité met en cache la liste complète des autorisations dans sa mémoire privée pour l'application en cours afin qu'elle n'ait pas à rester connectée. Selon la durée de la session de connexion, il peut s'agir d'une opération ponctuelle qui ne se répète jamais.

Quoi que vous fassiez, n'essayez pas d'inventer votre propre protocole de sécurité ou d'utiliser la sécurité par l'obscurité. Vous ne pourrez jamais écrire un meilleur algorithme pour cela que ceux qui sont actuellement disponibles et gratuits. De plus, les gens font confiance à des algorithmes bien connus. Donc, si vous dites que votre bibliothèque de sécurité fournit une autorisation et une authentification pour les applications mobiles locales en utilisant une combinaison de jetons cryptés SSL, HTTPS, SpringSecurity et AES, vous aurez immédiatement une crédibilité sur le marché.

J'espère que cela vous aidera et bonne chance dans votre entreprise. Si vous souhaitez plus d'informations, faites-le moi savoir - j'ai écrit pas mal d'applications Web basées sur Spring Security, les ACL et autres.

Gary Rowe
la source
Merci, bonne information. Quelques questions. Premièrement, si l'écoute clandestine est acceptable (je ne sais pas si elle l'est / ne l'est pas, mon application en tête n'a pas d'informations personnelles / précieuses, mais si c'était le cas, ma justification changerait), HTTPS est-il réellement nécessaire?
jsuggs
Vous pouvez faire fonctionner l'ensemble du système en dehors de HTTPS si vous le souhaitez. HTTPS sert uniquement à protéger les informations secrètes, je suppose donc que pendant la phase d'authentification, vous le feriez via HTTPS pour fournir une garantie que votre nom d'utilisateur / mot de passe / secret est gardé secret. Une fois le jeton remis dans la réponse, d'autres demandes peuvent être effectuées en clair si les informations contenues dans le flux (qui nécessitaient une authentification pour obtenir) ne nécessitent pas de protection contre les écoutes indiscrètes.
Gary Rowe
De plus, cette description du protocole d'authentification CAS peut être utile: jasig.org/cas/protocol
Gary Rowe
9

Twitter a résolu le problème des applications externes dans oAuth en prenant en charge une variante qu'ils appellent xAuth . Malheureusement, il existe déjà une pléthore d'autres schémas portant ce nom, il peut donc être difficile à résoudre.

Le protocole est oAuth, sauf qu'il ignore la phase de demande de jeton et émet simplement immédiatement une paire de jetons d'accès dès réception d'un nom d'utilisateur et d'un mot de passe. ( À partir de l' étape E ici .) Cette première demande et réponse doivent être sécurisées- il envoie le nom d'utilisateur et le mot de passe en texte clair et reçoit le jeton d'accès et le jeton secret. Une fois la paire de jetons d'accès configurée, le fait que l'échange de jetons initial se soit fait via le modèle oAuth ou le modèle xAuth n'a pas d'importance pour le client et le serveur pour le reste de la session. Cela présente l'avantage de pouvoir tirer parti de l'infrastructure oAuth existante et d'avoir pratiquement la même implémentation pour les applications mobiles / Web / de bureau. Le principal inconvénient est que l'application a accès au nom d'utilisateur et au mot de passe du client, mais il semble que vos exigences exigent cette approche.

Dans tous les cas, j'aimerais être d'accord avec votre intuition et celle de plusieurs autres répondants ici: n'essayez pas de construire quelque chose de nouveau à partir de zéro. Les protocoles de sécurité peuvent être faciles à démarrer mais sont toujours difficiles à bien faire, et plus ils deviennent compliqués, moins vos développeurs tiers sont susceptibles de pouvoir les mettre en œuvre contre eux. Votre protocole hypothétique est très similaire à o (x) Auth - api_key / api_secret, nonce, sha1 hashing - mais au lieu de pouvoir utiliser l'une des nombreuses bibliothèques existantes, vos développeurs vont devoir lancer la leur.

Lantius
la source
2
Je dois également souligner qu'il semble que le point de terminaison 'skip request token' va être dans oAuth 2, il est répertorié dans le projet actuel comme le type d'octroi d'accès "mot de passe". Voir la section 4.1.2: tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.1.2
lantius
Comme je l'ai mentionné à Lonra, je me penche davantage sur xAuth et plus particulièrement pour les raisons que vous avez mentionnées à la fin ... les développeurs peuvent vous «prêtes à l'emploi» des outils / bibliothèques oAuth pour interagir avec mon API, ce qui est «une bonne chose» .
jsuggs
6

Super tard à la fête mais je voulais ajouter quelques points supplémentaires à considérer pour toute personne intéressée par cette question. Je travaille pour une entreprise qui propose des solutions de sécurité API mobiles ( approv ), donc tout ce domaine est vraiment pertinent pour mes intérêts.

Pour commencer, la chose la plus importante à prendre en compte lors de la tentative de sécurisation d'une API mobile est de savoir combien cela vaut pour vous. . La bonne solution pour une banque est différente de la bonne solution pour quelqu'un qui ne fait que s'amuser.

Dans la solution proposée, vous mentionnez qu'un minimum de trois paramètres sera requis:

  • apikey - remis au développeur lors de l'inscription
  • horodatage - sert également d'identifiant unique pour chaque message pour un apikey donné
  • hash - un hachage de l'horodatage + l'apisecret

L'implication de ceci est que pour certains appels d'API, aucun nom d'utilisateur / mot de passe n'est requis. Cela peut être utile pour les applications où vous ne souhaitez pas forcer une connexion (navigation dans les boutiques en ligne par exemple).

Il s'agit d'un problème légèrement différent de celui de l'authentification des utilisateurs et s'apparente davantage à l'authentification ou à l'attestation du logiciel. Il n'y a pas d'utilisateur, mais vous voulez toujours vous assurer qu'il n'y a pas d'accès malveillant à votre API. Vous utilisez donc votre secret API pour signer le trafic et identifier le code d'accès à l'API comme authentique. Le problème potentiel de cette solution est que vous devez ensuite révéler le secret de chaque version de l'application. Si quelqu'un peut extraire le secret, il peut utiliser votre API, se faire passer pour votre logiciel mais faire ce qu'il veut.

Pour contrer cette menace, vous pouvez faire un tas de choses en fonction de la valeur des données. L'obfuscation est un moyen simple de rendre plus difficile l'extraction du secret. Il existe des outils qui le feront pour vous, plus encore pour Android, mais vous devez toujours avoir du code qui génère votre hachage et une personne suffisamment qualifiée peut toujours simplement appeler la fonction qui effectue le hachage directement.

Un autre moyen de limiter l'utilisation excessive d'une API qui ne nécessite pas de connexion consiste à limiter le trafic et potentiellement identifier et bloquer les adresses IP suspectes. La quantité d'effort que vous souhaitez déployer dépendra en grande partie de la valeur de vos données.

Au-delà de cela, vous pouvez facilement commencer à entrer dans le domaine de mon travail quotidien. Quoi qu'il en soit, c'est un autre aspect de la sécurisation des API que je pense être important et que je voulais signaler.

Le pragmatiste
la source