Préface
Mon application mobile permet aux utilisateurs de créer des comptes sur mon service. En plus de pouvoir me connecter avec des fournisseurs d'authentification externes, comme Facebook, je veux donner à l'utilisateur la possibilité de créer un compte en utilisant une adresse e-mail.
Normalement, tous les appels vers mon service Web sont authentifiés via une authentification de base via HTTPS. Cependant, la fonction de création de compte (également via HTTPS) n'a pas d'authentification - car l'utilisateur n'a pas encore d'informations d'identification.
Si j'écrivais un site Web, j'utiliserais Captcha pour empêcher ma base de données d'être remplie de faux comptes via un script.
Question
Comment puis-je vérifier que les nouvelles demandes d'utilisateurs proviennent d'une instance de mon application et non d'un bot?
Si toutes les données sont envoyées via HTTPS, est-il suffisant que l'application ait un mot de passe stocké pour dire "hé, c'est moi!"? Quelles sont les meilleures pratiques pour faire quelque chose comme ça?
Élaboration
Le serveur est écrit en Java utilisant Spring Framework et Spring Security. Il est hébergé sur App Engine. Le coût est une préoccupation (à la fois réseau et calcul). L'application est un jeu mobile. Je le fais ne stocke pas d'informations sensibles comme les numéros de carte de crédit. Cependant, je garde une trace des achats des utilisateurs sur les magasins Apple et Android. Ma plus grande préoccupation est l'expérience du joueur. Je ne veux pas qu'un hacker fasse tomber le système et ruine le plaisir de quelqu'un du jeu. Je dois également m'assurer que le joueur fait face au moins d'obstacles possible lors de la création d'un compte.
Mise à jour/Clarification
Je cherche un moyen de m'assurer que tous les appels au service proviennent d'une instance de ma demande. Les comptes d'utilisateurs sont déjà protégés car le service sans état requiert qu'ils envoient leurs informations d'identification à chaque demande. Il n'y a pas de sessions et pas de cookies.
Je dois arrêter le bot-spam sur les appels non sécurisés, tels que create-new-account. Je ne peux pas utiliser captcha car il ne rentre pas dans le flux de l'application.
L'essentiel est que vous devrez intégrer un secret dans votre application. C'est une triste vérité que DRM (qui est plus ou moins ce que vous essayez d'atteindre) est impossible. Une personne ayant accès à votre application toujours pourra récupérer le secret intégré, quoi que vous fassiez pour le protéger.
Cela dit, il y a beaucoup de choses que vous pouvez faire pour rendre votre secret intégré très difficile à récupérer.
Construisez-le à l'exécution - Ne stockez pas le secret dans une chaîne ou un fichier de configuration n'importe où dans votre application. Au lieu de cela, dérivez-le d'une série de calculs lors de l'exécution. Cela empêche les attaquants de simplement parcourir votre application avec un hexeditor.
Ne jamais l'envoyer par câble - Utilisez un système de réponse au défi d'une sorte avec un nonce> 128 bits, de cette façon un attaquant ne peut pas MitM le flux SSL ( ce qui est facile quand il contrôle l'appareil mobile rappelez-vous) et voyez le secret en clair.
Dans tous les cas, essayez de trouver un mécanisme d'embrouillage des clés et un protocole d'authentification éprouvés. Ne roulez pas le vôtre.
La plupart du temps, vous ne pouvez pas vérifier que c'est "votre application": reverse engineering fonctionne, donc quiconque a accès à votre application (par exemple, il peut la télécharger sur son téléphone) peut piquer ses entrailles et l'imiter avec son PC. @Lynks vous donne quelques conseils sur la façon dont cette ingénierie inverse peut devenir une entreprise plus frustrante, mais ne vous y trompez pas: si l'attaquant est suffisamment motivé, ces mécanismes le ralentiront au plus de quelques jours.
Lorsqu'il n'y a pas de bonne réponse à une question, il peut être utile de changer de terrain pour que la question change. Ici, le problème principal d'essayer de vous assurer que "votre application" fonctionne sur le côté client est qu'il existe une chose telle que "votre application": si quelqu'un ouvre le contenu de cette application, il apprend tout ce qui est pour en savoir plus sur toutes les instances de cette application partout.
Voici donc une tentative de solution à votre problème. Marquez chaque instance d'application avec une valeur distincte. Le "balisage" signifie ici que lorsque l'utilisateur télécharge l'application, un jeton est intégré à l'application et une nouvelle valeur de jeton est créée pour chaque téléchargement. Pour que chaque utilisateur obtienne sa propre application avec token. L'idée étant que le jeton devra être présenté à votre serveur pour la création de compte, et si votre serveur voit trop de demandes avec le même jeton, il peut automatiquement les rejeter - interdisant ce jeton spécifique.
Ensuite, pour continuer à créer de nombreux comptes automatiquement, l'attaquant devrait également automatiser le téléchargement de nouvelles instances d'application (chacune avec sa propre valeur de jeton) et la récupération de la valeur de jeton hors de l'application téléchargée. En supposant que votre serveur se trouve à l'autre bout du téléchargement de l'application, vous pouvez également détecter ce téléchargement de masse et le bloquer à partir de là.
Pour que ce schéma fonctionne, vous devez être en mesure de créer des valeurs de jeton sur le serveur de téléchargement d'applications, à la demande (cela peut cependant être difficile à configurer avec le système d'installation des applications sur les smartphones existants), et de telle sorte que le serveur de création de compte puisse décider si une valeur symbolique est authentique ou non. HMAC est le bon outil cryptographique pour cela.
Soyez conscient que ce type de solution est loin d'être parfait. Ce sont des jeux et des astuces pour "élever la barre" pour l'attaquant: si vous concevez et installez un système comme celui que je décris, un attaquant qui réussit devra automatiser le téléchargement de l'application à partir de nombreuses adresses IP distinctes, pour rester sous le radar de votre heuristique pour détecter de telles choses; puis automatisez également l'ingénierie inverse pour récupérer les valeurs des jetons (utilisez pour cela les techniques expliquées par @Lynks); puis transférez les valeurs à ses robots qui créent des comptes. Tout cela est toujours théoriquement réalisable: après tout, utilisateurs humains peut télécharger l'application et créer des comptes, et il n'y a aucun moyen de vraiment faire la différence, de l'extérieur, entre un utilisateur humain moyen , un chimpanzé et un bot.
Mais si vous pouvez rendre l'attaque suffisamment complexe pour que l'attaquant la juge "ne vaut pas la peine", alors vous gagnez.
Si j'écrivais un site Web, j'utiliserais Captcha pour empêcher ma base de données d'être remplie de faux comptes via un script.
Incluez donc cela dans l'API. Lorsqu'un utilisateur souhaite créer un compte:
Le client demande que le nouveau compte soit créé et envoie la réponse CAPTCHA avec cette demande.
Vous pouvez également utiliser quelque chose comme HashCash pour rendre plus difficile pour quelqu'un de monter une attaque par force brute, assurez-vous simplement que le HashCash peut être généré plus rapidement qu'un utilisateur ne peut raisonnablement terminer le formulaire.
Vous avez besoin d'une authentification d'application similaire. C'est le même concept que l'authentification que vous faites pour les appels API avec des sites comme Twitter, Facebook et Foursquare. Ils ne permettent à personne de simplement interroger leur API. Au lieu de cela, ils génèrent une clé API et un secret API pour votre application. Si votre application présente ces clés au serveur, vous êtes autorisé à utiliser leurs API.
Si vous voulez vous assurer que les gens utilisent l'API uniquement via votre application, vous devrez modifier périodiquement tous les points de terminaison, et également les modifier dans votre application client. Quiconque a créé sa propre application client à l'aide de votre API se retrouve désormais avec une application client qui ne fonctionne pas. Maintenant, ils pourraient reconstruire leur application avec les points de terminaison API corrects, mais si vous continuez à changer les points de terminaison, ils finiront par abandonner.
Une alternative pourrait également être d'avoir à la fois les anciens points de terminaison API qui ne renvoient un message d'erreur que lorsque quelqu'un essaie de les appeler et les nouveaux points de terminaison api (modifiés) qui sont utilisés par votre application client mise à jour. Bannissez toutes les adresses IP qui utilisent toujours vos anciens points de terminaison API de sorte que lorsque le pirate/voleur met à jour son application cliente tierce pour correspondre à vos points de terminaison mis à jour, il ne restera plus de base d'utilisateurs car tous ceux qui utilisaient les anciens points de terminaison API sont désormais interdits. Cela découragera également cette personne de continuer à voler vos données en les affichant dans sa propre application cliente.