Création d’une API pour les applications mobiles – Authentification et autorisation

Vue d’ensemble

Je cherche à créer une API (REST) ​​pour mon application. Le but 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). Je me suis concentré sur la plupart des concepts fondamentaux, mais je cherche toujours des 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 (mais mes critères peuvent être mal interprétés, alors n’hésitez pas à les critiquer également). De plus, je souhaite que l’API soit la même pour toutes les plates-formes / applications qui la consumnt.

oAuth

Je vais aller de l’avant et jeter mon objection à oAuth, car je sais que ce sera probablement la première solution offerte. Pour les applications mobiles (ou plus spécifiquement les applications non-web), il semble tout simplement erroné de laisser l’application (pour accéder à un navigateur Web) pour l’authentification. De plus, il n’ya aucun moyen (je suis au courant) que le navigateur renvoie le rappel à l’application (en particulier multi-plateforme). Je connais quelques applications qui le font, mais cela ne semble pas correct et fait une pause dans l’application UX.

Exigences

  1. L’utilisateur entre son 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 de l’authentification est intuitif pour les développeurs.
  4. Le mécanisme est sécurisé à la fois pour l’utilisateur final (ses identifiants de connexion ne sont pas exposés) et pour le développeur (ses informations d’identification d’application ne sont pas exposées).
  5. Si possible, ne nécessite pas https (en aucun cas une exigence ssortingcte).

Mes reflections 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 minimum trois parameters.

  • apikey – donné au développeur lors de l’enregistrement
  • timestamp – double l’identifiant unique de chaque message pour un apikey donné
  • hash – un hash de l’horodatage + l’apisecret

L’apikey est nécessaire pour identifier l’application qui émet la demande. L’horodatage agit de la même manière que l’oauth_nonce et évite / atténue les attaques par répétition. Le hachage garantit que la demande a bien été émise par le propriétaire du document en question.

Pour les demandes authentifiées (celles effectuées pour le compte d’un utilisateur), je ne suis toujours pas d’accord entre une route access_token ou une combinaison de hachage de nom d’utilisateur et de mot de passe. De toute façon, à un moment donné, un nom d’utilisateur / mot de passe sera requirejs. Ainsi, le hachage de plusieurs informations (apikey, apisecret, timestamp) + le mot de passe sera utilisé. J’adorerais les commentaires sur cet aspect. Pour info, ils doivent d’abord hacher le mot de passe, car je ne stocke pas les mots de passe dans mon système sans hachage.

Conclusion

FYI, ce n’est pas une demande pour la façon de construire / structurer l’API en général seulement comment gérer l’authentification et l’autorisation uniquement dans une application.

Pensées aléatoires / Questions bonus

Pour les API qui requièrent uniquement un fichier apikey dans le cadre de la requête, comment empêcher une personne autre que le propriétaire d’apikey de voir l’apikey (depuis l’envoi en clair) et de faire des requêtes excessives pour dépasser les limites d’utilisation? Peut-être que je suis juste en train de penser 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 d’Apikey? Dans mon cas, c’était le but de l’apisecret, il n’est jamais montré / transmis sans être haché.

En parlant de hashes, qu’en est-il de md5 vs hmac-sha1? Est-il vraiment important que toutes les valeurs soient hachées avec des données suffisamment longues (par exemple apisecret)?

J’avais déjà envisagé d’append un sel par utilisateur / ligne à mon hash de mot de passe utilisateur. Si je devais le faire, comment l’application pourrait-elle créer un hachage correspondant sans connaître le sel utilisé?

La façon dont je pense faire la connexion dans mes projets est la suivante:

  1. Avant de se connecter, l’utilisateur demande un login_token au 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 login_token pour obtenir une valeur, puis retourne à la fois le login_token et le hachage combiné.

  3. Le serveur vérifie que login_token a été généré, le retirant de sa liste de login_token valide. Le serveur combine alors son hachage stocké du mot de passe de l’utilisateur avec le login_token et 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 transmis en clair, le hachage du mot de passe est seulement transmis en clair lors de la création du compte. à l’abri des attaques par rejeu car le login_token est supprimé de la firebase database lors de son utilisation.

C’est un tas de questions en un, je suppose que beaucoup de gens n’ont pas réussi à lire jusqu’à la fin 🙂

Mon expérience de l’authentification de service Web est que les gens l’utilisent généralement de manière excessive, et les problèmes ne sont que les mêmes que ceux que vous rencontrez sur une page Web. Les options très simples possibles incluraient https pour l’étape de connexion, renvoyer un jeton, exiger qu’il soit inclus dans les futures requêtes. 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 pivoter / expirer les jetons fréquemment, vérifiez que les requêtes proviennent du même bloc IP (cela peut être compliqué, car les utilisateurs mobiles se déplacent entre les cellules), combinez avec une clé API ou similaire. Vous pouvez également faire l’étape “demande clé” de oauth (quelqu’un a déjà suggéré cela dans une réponse précédente et c’est une bonne idée) avant d’authentifier l’utilisateur, et l’utiliser comme clé requirejse pour générer le jeton d’access.

Une alternative que je n’ai pas encore utilisée mais dont j’ai beaucoup entendu parler en tant qu’alternative à oAuth adaptée aux périphériques est xAuth . Jetez-y un coup d’oeil et si vous l’utilisez, je serais très intéressé par vos impressions.

Pour le hachage, sha1 est un peu mieux, mais ne vous y attardez pas – tout ce que les appareils peuvent facilement (et rapidement au sens des performances) est probablement correct.

J’espère que ça aide, bonne chance 🙂

Twitter a abordé le problème des applications externes dans oAuth en prenant en charge une variante appelée xAuth . Malheureusement, il existe déjà une pléthore d’autres systèmes avec ce nom, ce qui peut créer de la confusion.

Le protocole est oAuth, sauf qu’il ignore la phase de jeton de demande et émet simplement immédiatement une paire de jetons d’access à la réception d’un nom d’utilisateur et d’un mot de passe. (À partir de l’ étape E ici ). Cette demande initiale et cette réponse doivent être sécurisées – il s’agit d’envoyer le nom d’utilisateur et le mot de passe en texte brut et de recevoir le jeton d’access et le jeton secret. Une fois la paire de jetons d’access configurée, le fait que l’échange de jetons initial se soit fait via le modèle oAuth ou le modèle xAuth est sans importance pour le client et le serveur pour le rest de la session. Cela présente l’avantage de pouvoir tirer parti de l’infrastructure oAuth existante et d’avoir une implémentation presque identique pour les applications mobiles / Web / de bureau. Le principal inconvénient est que l’application a access au nom d’utilisateur et au mot de passe du client, mais il semble que vos exigences imposent cette approche.

En tout cas, je suis d’accord avec votre intuition et celle de plusieurs autres intervenants: n’essayez pas de créer quelque chose de nouveau à partir de rien. Les protocoles de sécurité peuvent être faciles à démarrer, mais ils sont toujours difficiles à faire, et plus ils sont compliqués, moins vos développeurs tiers sont susceptibles de les implémenter. 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 devront déployer leur propre méthode.

Vous recherchez donc une sorte de mécanisme d’authentification côté serveur pour gérer les aspects d’authentification et d’autorisation d’une application mobile?

En supposant que ce soit le cas, alors je l’approcherais 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 indiscrètes.
  2. Il sera basé sur une combinaison de RESTEasy , Spring Security et CAS (pour la connexion unique entre plusieurs applications).
  3. Il fonctionnera avec les navigateurs et les applications client Web
  4. Une interface de gestion de compte Web permettra aux utilisateurs de modifier leurs informations et les administrateurs (pour des applications particulières) de 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 (Java, ObjectiveC, C, etc.).
  2. La bibliothèque doit gérer la formation des requêtes HTTPS en utilisant les API disponibles pour la plate-forme donnée (par exemple, Java utilise URLConnection, etc.)
  3. Les consommateurs de la bibliothèque d’authentification et d’autorisation générale (c’est tout ce qu’elle est) coderont pour une interface spécifique et ne seront pas contents si elle change, 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 terminée, comment allez-vous le faire? Eh bien, ce n’est pas si difficile de créer un système d’authentification et d’autorisation basé sur les technologies listées du côté serveur avec un client de navigateur. En combinaison avec HTTPS, les frameworks fourniront un processus sécurisé basé sur un jeton partagé (généralement présenté sous la forme d’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 est effectuée.

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 dispose d’une liste de contrôle d’access (ACL) définie contrôlant l’access d’exécution aux appels de méthode. Par exemple, un utilisateur donné peut lire une collection à partir d’une méthode, mais sa liste de contrôle d’access permet uniquement d’accéder aux objects dont le nom contient un Q, de sorte que certaines données de la collection sont extraites par l’intercepteur de sécurité. Dans Java, c’est simple, il vous suffit d’utiliser les annotations Spring Security sur le code appelant et d’implémenter un processus de réponse ACL approprié. Dans d’autres langues, vous êtes seul et devrez probablement fournir un code de sécurité standard qui appelle votre bibliothèque de sécurité. Si la langue prend en charge AOP (Programmation Orientée Aspect), utilisez-la au maximum pour cette situation.
  2. La bibliothèque de sécurité met en cache la liste complète des permissions dans sa mémoire privée pour l’application en cours, afin qu’elle n’ait pas à restr connectée. Selon la durée de la session de connexion, il peut s’agir d’une opération unique 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 obscurité. Vous ne serez jamais capable d’écrire un meilleur algorithme pour cela que ceux qui sont actuellement disponibles et gratuits. En outre, 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 SSL, HTTPS, SpringSecurity et AES, vous aurez immédiatement une crédibilité sur le marché.

J’espère que cela aide, 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.

Super tard pour la fête mais je voulais append quelques points supplémentaires à prendre en compte pour quiconque s’intéresse à ce problème. Je travaille pour une entreprise spécialisée dans les solutions de sécurité API mobiles ( approov ), donc tout ce domaine est sans aucun doute pertinent pour mes intérêts.

Pour commencer, la chose la plus importante à prendre en compte lorsque vous essayez de sécuriser une API mobile est de savoir combien elle vaut pour vous . La bonne solution pour une banque est différente de la bonne solution pour quelqu’un qui fait simplement des choses pour le plaisir.

Dans la solution proposée, vous mentionnez qu’un minimum de trois parameters sera requirejs:

  • apikey – donné au développeur lors de l’inscription
  • timestamp – double l’identifiant unique de chaque message pour un apikey donné
  • hash – un hash de l’horodatage + l’apisecret

Cela implique que pour certains appels d’API, aucun nom d’utilisateur / mot de passe n’est requirejs. Cela peut être utile pour les applications où vous ne voulez 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 ressemble plus à 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’access malveillant à votre API. Vous utilisez donc votre secret API pour signer le trafic et identifier le code accédant à l’API comme authentique. Le problème potentiel avec cette solution est que vous devez ensuite divulguer le secret dans chaque version de l’application. Si quelqu’un peut extraire le secret, il peut utiliser votre API, se faire passer pour votre logiciel, mais en faisant ce qu’il veut.

Pour contrer cette menace, vous pouvez faire tout un tas de choses en fonction de la valeur des données. L’obscurcissement 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 un code qui génère votre hash et un individu suffisamment qualifié peut toujours appeler la fonction qui effectue le hachage directement.

Une autre façon d’atténuer l’utilisation excessive d’une API ne nécessitant pas de connexion consiste à limiter le trafic et à identifier et bloquer les adresses IP suspectes. La quantité d’efforts que vous voulez déployer dépendra largement 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 j’estime important et que l’on souhaite signaler.