J'ai développé une application qui prendra en charge de nombreux utilisateurs. Le problème est que je ne peux pas comprendre comment authentifier le client/utilisateur.
Je crée une application comme http://quickblox.com/ où je donnerai des informations d'identification à mes utilisateurs et ils les utiliseront pour construire [~ # ~] n [~ # ~] applications dans lesquelles ils ne peuvent pas mettre leur nom d'utilisateur et leur mot de passe pour s'authentifier.
Supposons que cela se passe comme suit. (Tout comme QuickBlox)
1. L'utilisateur crée un compte sur mon site Web.
2. L'utilisateur peut créer N clés API et sécréter des informations d'identification. (Pour plusieurs applications)
3. L'utilisateur utilisera ces informations d'identification dans ses applications (Android, iOS, Javascript, etc.) pour parler avec mes API REST.
(Les API REST ont un accès en lecture et en écriture.)
Ma préoccupation?
Les utilisateurs mettront leurs informations d'identification (clé API et clé secrète) dans les applications qu'ils créent, que se passe-t-il si quelqu'un obtient ces clés et essaie d'imiter l'utilisateur? (En décompilant l'APK ou en consultant directement le code JavaScript.
Ai-je tort quelque part?
Je suis confus pour concevoir ce mécanisme utilisateur à trois niveaux.
J'ai conçu des API REST au cours des dernières années. Vous vous inquiétez trop. Récemment, un autre utilisateur de ce forum a posé une question, où il s'inquiétait stockage des points de terminaison URI dans son code JavaScript côté client .
Les mêmes règles s'appliquent à vous que celles applicables au développeur JavaScript. Si vous autorisez des personnes de l'extérieur à intégrer votre API, votre API a la même visibilité qu'un site Web normal et vous devez la traiter de la même manière.
Citation de la réponse originale:
Lorsque vous créez un site Web et que vous ne voulez pas que les utilisateurs fassent quelque chose, vous n'implémentez pas cette fonctionnalité ou interdisez à certains utilisateurs de l'utiliser. Avec une API REST qui devrait avoir des points de terminaison publics, c'est à peu près la même chose, vous devez la traiter comme un site Web public.
Votre API REST doit être suffisamment robuste pour ne pas autoriser des opérations non valides, telles que l'accès aux données d'un autre utilisateur.
Vous devez concevoir vos jetons d'accès à l'application pour n'autoriser que les opérations que vous souhaitez autoriser. Vous pouvez avoir deux types de jetons d'accès:
Mais qu'est-ce que quelqu'un déconstruit le code source, prend les jetons de l'application, découvre quels sont les points de terminaison publics et abuse de votre service Web?
À moins que vous ne gériez directement le développement des applications consommant votre API, rien n'interdit vraiment aux gens d'abuser de votre API de la même manière directement depuis l'application.
Votre problème n'est pas tant technique que commercial.
Disons que vous avez votre API, que vous vendez à vos clients (les développeurs d'applications) pour un montant forfaitaire de 100 £ par an, un accès illimité.
Et bien évidemment, je peux acheter votre service à 100 £ et le revendre à 10 personnes à 50 $ chacune. Tu ne veux pas ça! vous essayez donc de penser à une restriction qui vous permettra de vendre votre API sans qu'elle soit ouverte à l'arbitrage.
Si vous limitez simplement le nombre d'applications, un client peut créer une seule application qui accepte les connexions d'autres applications et les transmet.
Si vous limitez les utilisateurs, encore une fois, le client peut masquer les utilisateurs derrière sa propre authentification et apparaître comme un seul utilisateur.
Ce que vous devez faire est de répercuter le coût de chaque appel API sur votre client. c'est-à-dire facturer par appel API ou définir un quota d'appels par an.
Cela pousse le même problème d'arbitrage sur vos clients. Cela les oblige à mettre en place des mesures pour empêcher leurs utilisateurs de voler leurs clés. Dans ce cas, cachez votre API derrière leur propre API authentifiée par l'utilisateur.
Les autres réponses semblent toutes suggérer que le problème du stockage d'un secret dans une application sur des appareils grand public n'est pas résoluble.
Bien sûr que ça l'est.
Deux principes (les détails de mise en œuvre suivront):
Étant donné que, si le client fait une demande au point de terminaison d'authentification avec des informations d'identification et que le serveur l'authentifie, le serveur peut générer un jeton --- temporaire (temporaire qui signifie temporel). Ce jeton doit être mémorisé dans le client et envoyé avec les demandes suivantes.
Vous aurez besoin d'un mécanisme pour "actualiser" périodiquement le jeton, c'est-à-dire en obtenir un nouveau. Créez simplement un point de terminaison REST qui permet de générer un nouveau jeton à partir d'un point existant, pour éviter d'avoir à vous réauthentifier à partir des informations d'identification.
Si vous essayez d'éviter que l'utilisateur final ne se réauthentifie, cette authentification peut être une configuration initiale unique dans l'application lors de son installation.
Cette solution évite simplement la nécessité de stocker un jeton statique incorporé dans le binaire de l'application. Un jeton est généré à la volée par le serveur uniquement en réponse à une authentification réussie. Pour qu'un utilisateur malveillant inspecte votre application et tente d'obtenir un accès API non autorisé, il devra toujours s'authentifier comme tout le monde.
D'après ce que je sais, ce que vous avez mentionné est la seule façon de procéder. L'application stockant la clé est certainement un risque, mais il existe différentes façons de le contourner. Vous pouvez toujours utiliser le magasin de clés pour stocker la clé, que le codage en dur, forçant ainsi une connexion unique.
En outre, vous devez envisager de lier une clé à un client.Par conséquent, si quelqu'un imite, vous devez disposer d'une couche de sécurité pour vérifier le client, la clé et les agents utilisateurs pour bloquer immédiatement la demande. Ayez un cas d'utilisation pour réémettre ou vous assurer que les clés ne sont pas imitées.
Si vous avez des clés uniques par application, vous ne pouvez les utiliser que lors d'une authentification de connexion initiale, lancée par le client, après quoi vous passez à un jeton d'authentification unique par application mobile.
Votre serveur modifie (lance) le jeton de chaque application cliente de temps à autre (périodiquement, plus/moins un certain délai aléatoire flou/aléatoire, par exemple). Le jeton roulant n'est connu qu'entre le serveur et le client authentifié.
Les nouveaux jetons sont retournés piggy-back sur les réponses régulières. Chaque fois que la réponse contient un nouveau jeton, l'application réceptrice doit passer à son utilisation dans les demandes suivantes.
Chaque fois que l'échange avec un client se désynchronise (une erreur de protocole quelconque), votre serveur demandera une ré-authentification (via une réponse d'erreur à la prochaine demande du client, ou s'appuiera sur la réponse valide à la demande du client, pour exemple).
L'authentification initiale initiée par les clients alors qu'un jeton roulant est activement utilisé doit être considérée avec suspicion - cela pourrait très bien être une tentative de mimétisme. Je ne l'autoriserais que si l'échange devient inactif pendant un intervalle plus long que prévu, ce qui pourrait, par exemple, être causé par une panne/redémarrage du client avec une nouvelle instance qui n'a pas le jeton roulant.
Il serait encore mieux de conserver le jeton du côté client de sorte qu'un client redémarré puisse continuer d'où son prédécesseur est parti - en réduisant considérablement l'ouverture pour l'imitation.
Un tel schéma rendrait l'imitation au moins assez difficile - le client imitant devrait prévoir exactement la fenêtre lorsque le client autorisé arrêterait d'envoyer des demandes suffisamment longtemps pour que le serveur décide qu'il est acceptable d'accepter une nouvelle authentification client avec la clé prescrite. De telles demandes en dehors de la fenêtre autorisée peuvent être utilisées comme détection de tentatives de mimétisme et éventuellement initier certaines contre-mesures (liste noire IP, etc.).
Si vous comptez donner à vos clients des jetons d'autorisation pour mettre leurs applications, il sera toujours théoriquement possible pour quelqu'un de procéder à une rétro-ingénierie de l'application et de les extraire. Pour éviter cela, vous auriez besoin d'un mécanisme qui ne nécessiterait pas de secret dans l'application cliente. C'est délicat. Je peux cependant vous suggérer quelques options.
Vous avez un problème une fois que vous avez donné les informations d'identification, vous n'avez aucun contrôle sur la sécurité de leur stockage. De plus, si vous demandez à l'utilisateur de vous envoyer les informations d'identification, quelqu'un peut MITM votre connexion et voler les jetons directement sans se soucier de l'ingénierie inverse de l'application.
Une façon de rendre plus difficile l'extraction de votre jeton d'autorisation est de le masquer. Cela soulève simplement la barre, mais ne le rend pas impossible, et pour ce faire, vous devrez garder le contrôle du secret. Vous pouvez implémenter une bibliothèque contenant les informations secrètes et spécifique à chaque client. Vous pouvez utiliser la bibliothèque pour communiquer avec vos serveurs et vous n'aurez peut-être même pas à dire à votre utilisateur les informations secrètes, elles pourraient simplement être intégrées dans la bibliothèque. Cela ne résout pas le problème de l'ingénierie inverse de votre bibliothèque, mais cela vous permet de contrôler le niveau d'obscurcissement. Un inconvénient est qu'une fois qu'une personne a brisé l'obscurcissement dans la bibliothèque, elle peut attaquer n'importe laquelle de vos bibliothèques, sauf si vous écrivez du code qui rend chaque bibliothèque significativement différente. Cela introduit son propre ensemble de problèmes.
Cela peut s'écarter légèrement de la portée de votre question, mais cela est lié à la sécurité de votre jeton, je vais donc le mentionner. Pour éviter le vol trivial du jeton sur le câble, vous ne voulez probablement pas envoyer le jeton directement, mais vous pouvez signer le trafic à l'aide d'une fonction HMAC. Vous pouvez vérifier la validité du message en calculant le HMAC du message sur le serveur et en le comparant au HMAC envoyé par le client. Vous utiliseriez le jeton comme clé de la fonction HMAC afin que seule une personne connaissant le jeton puisse signer le trafic. C'est mieux pour la sécurité de votre token car vous ne l'envoyez jamais directement au serveur, il ne peut donc pas être intercepté et volé directement. Pour plus d'informations sur HMACS, consultez cette question: https://security.stackexchange.com/questions/20129/how-and-when-do-i-use-hmac/20301
Aucune solution de sécurité ne sera imprenable, vous devez décider combien cela vous coûtera à mettre en œuvre par rapport à la probabilité et au coût d'être compromis.
Vous citer:
Je ne peux pas comprendre comment authentifier le client/utilisateur ... dans lequel ils ne peuvent pas mettre leur nom d'utilisateur et leur mot de passe pour s'authentifier.
Maintenant, c'est un peu une contradiction, n'est-ce pas?;)
Comme d'autres l'ont dit, vous ne pouvez pas. Si une application utilise une clé API, on peut la décompiler comme vous le dites pour obtenir la ou les clés et l'utiliser également.
Outre la nécessité d'une authentification utilisateur supplémentaire, vous ne pouvez que limiter les dommages: