web-dev-qa-db-fra.com

Comment une application doit-elle stocker ses informations d'identification

Le contexte

Lors du développement d'applications de bureau, vous devrez parfois stocker des informations d'identification quelque part pour pouvoir authentifier votre application. Un exemple de ceci est un ID d'application Facebook + secret , un autre est les informations d'identification MySQL.

Le stockage de ce texte brut dans le code source des applications n'offre aucune véritable sécurité car ce n'est pas trop compliqué de désosser un programme . La collecte des informations d'identification d'un serveur ne fera pas l'affaire non plus, car les pirates peuvent facilement effectuer eux-mêmes des demandes. Le chiffrement des informations d'identification stockées ne fera pas non plus de différence, car l'application devra avoir accès à la clé de déchiffrement pour pouvoir utiliser les informations d'identification.


Question

Comment stocker en toute sécurité les informations d'identification spécifiques à une application? De préférence multi-OS.

Remarque: Le langage pertinent est Java, cependant, je pense (pense) que c'est une question indépendante du langage.

36
Zar

Ne codez jamais en dur les mots de passe ou les clés de chiffrement dans votre programme.

La règle générale est la suivante: les seules informations d'identification que vous devez stocker sur la machine d'un utilisateur sont les informations d'identification associées à cet utilisateur, par exemple, les informations d'identification qui permettent à cet utilisateur de se connecter à son compte.

Vous ne devez pas stocker votre informations d'identification de développeur sur la machine de l'utilisateur. Ce n'est pas sûr.

Vous devez supposer que tout ce qui est stocké sur la machine de l'utilisateur est connu de l'utilisateur ou peut facilement être appris par l'utilisateur. (C'est la bonne hypothèse: il n'est pas difficile de rétroconcevoir un binaire d'application pour apprendre les clés ou les secrets qui peuvent y être intégrés.)

Une fois que vous comprenez ce principe général, tout devient facile. Fondamentalement, vous devez ensuite concevoir le reste de votre système et votre protocole d'authentification afin que le logiciel client puisse s'authentifier en utilisant uniquement les informations d'identification qui peuvent être stockées en toute sécurité sur le client.

Exemple 1. Supposons que vous ayez un identifiant et une clé d'application Facebook, associés à votre application (c'est-à-dire associés à votre compte de développeur). Intégrez-vous l'ID et la clé de l'application dans le logiciel de bureau que vous livrez aux utilisateurs? Non! Absolument pas. Vous ne le faites certainement pas, car cela permettrait à n'importe lequel de vos utilisateurs d'apprendre votre ID et votre clé d'application et de soumettre leurs propres demandes, ce qui pourrait nuire à votre réputation.

Au lieu de cela, vous trouvez un autre moyen. Par exemple, vous pouvez configurer votre propre serveur qui a l'ID et la clé de l'application et qui est responsable de faire les demandes à la plate-forme Facebook (sous réserve des limitations appropriées et de la limitation des taux). Ensuite, votre client se connecte à votre serveur. Peut-être que vous authentifiez chaque client en demandant à chaque utilisateur de configurer son propre compte d'utilisateur sur votre serveur, en stockant les informations d'identification du compte sur le client et en demandant au client de s'authentifier à l'aide de ces informations d'identification.

Vous pouvez rendre cela totalement invisible pour l'utilisateur, en faisant en sorte que l'application cliente génère un nouveau compte d'utilisateur lors de la première exécution (en générant ses propres identifiants de connexion, en les stockant localement et en les envoyant au serveur). L'application cliente peut utiliser ces informations d'identification stockées pour se connecter à l'avenir (par exemple, via SSL) et se connecter automatiquement à chaque exécution ultérieure de l'application.

Remarquez comment la seule chose stockée sur la machine d'un utilisateur sont des informations d'identification qui permettent de se connecter au compte de cet utilisateur - mais rien qui permettrait de se connecter aux comptes d'autres personnes, et rien qui exposerait les clés d'application du développeur.

Exemple 2. Supposons que vous écriviez une application qui doit accéder aux données de l'utilisateur dans son compte Google. Leur demandez-vous leur nom d'utilisateur et leur mot de passe Google et les stockez-vous dans le stockage local de l'application? Vous pourriez: ce serait OK, car les informations d'identification de l'utilisateur sont stockées sur la machine de l'utilisateur. L'utilisateur n'est pas incité à essayer de pirater sa propre machine, car il connaît déjà ses propres informations d'identification.

Encore mieux: utilisez OAuth pour autoriser votre application. De cette façon, votre application stocke un jeton OAuth dans son stockage local d'application, qui permet à votre application d'accéder à le compte Google de l'utilisateur. Cela évite également la nécessité de stocker le mot de passe Google de l'utilisateur (qui est particulièrement sensible) dans le stockage local de l'application, ce qui réduit le risque de compromis.

Exemple 3. Supposons que vous écrivez une application qui a un backend de base de données MySQL qui est partagé entre tous les utilisateurs. Prenez-vous la base de données MySQL et l'intégrer dans le binaire de l'application? Non! N'importe lequel de vos utilisateurs peut extraire le mot de passe et accéder directement à votre base de données MySQL.

Au lieu de cela, vous configurez un service qui fournit les fonctionnalités nécessaires. L'application cliente se connecte au service, s'authentifie et envoie la demande au service. Le service peut ensuite exécuter cette requête sur la base de données MySQL. Le mot de passe MySQL reste stocké en toute sécurité sur la machine du serveur et n'est jamais accessible sur la machine d'un utilisateur. Le serveur peut imposer les restrictions ou le contrôle d'accès que vous souhaitez.

Cela nécessite que votre application cliente puisse s'authentifier auprès du service. Une façon de le faire consiste à demander à l'application cliente de créer un nouveau compte sur le service lors de la première exécution, de générer des informations d'authentification aléatoires et de se connecter automatiquement au service à chaque fois suivante. Vous pouvez utiliser SSL avec un mot de passe aléatoire, ou mieux encore, utiliser quelque chose comme SSL avec un certificat client unique pour chaque client.


L'autre règle est: vous ne codez pas les informations d'identification dans le programme. Si vous stockez des informations d'identification sur la machine de l'utilisateur, stockez-les dans un emplacement privé: peut-être un fichier de configuration ou dans un répertoire, de préférence un fichier qui n'est lisible que par cette application particulière ou cet utilisateur particulier (pas un fichier lisible par le monde).

30
D.W.

Il s'agit d'un problème de sécurité classique sans solution parfaite, juste imparfait, et se résume au problème plus général de la protection des logiciels contre la falsification et la rétro-ingénierie.

  1. Utilisez une méthode d'authentification externe que l'utilisateur doit fournir activement pour accéder aux informations d'identification: un mot de passe entré manuellement (dont le condensé de hachage, par exemple, est utilisé pour déchiffrer les informations d'identification), un dongle d'authentification sécurisé contenant un certificat et une clé privée correspondante qui doit être entré dans un port USB, un lecteur d'empreintes digitales fournissant la bonne empreinte digitale, etc. Idéalement, le résultat ne sera pas une simple réponse oui/non à votre programme, car cela peut être annulé/corrigé/usurpé, mais une valeur réelle (un clé cryptographique) nécessaire pour déchiffrer vos informations d'identification (ou tout ce que vous essayez de protéger), dérivées directement de l'authentificateur. Une approche multi-source dans laquelle la clé de déchiffrement est calculée à la volée à partir de diverses sources (quant aux sources, cela dépend vraiment de votre système) pourrait être encore meilleure.

  2. Obscurcissez fortement (automatiquement et massivement) votre programme pour contrecarrer la rétro-ingénierie. Il est vrai que les outils d'analyse statique sont devenus à la pointe de la technologie, mais il existe des outils d'obscurcissement [propriétaires, coûteux] (compilateurs d'obscurcissement, packers, etc.) qui rendent la rétro-ingénierie très longue, difficile et laborieuse, assez pour envoyer les attaquants à la recherche de cibles plus faciles. L'ajout de mécanismes de protection contre le débogage et les méthodes de résistance à la falsification peut encore renforcer la sécurité de votre programme. Il est vrai que Java en tant que langage de bytecode est particulièrement vulnérable à cet égard, car sa décompilation (par rapport à la décompilation/désassemblage du code natif) est plutôt simple.

7
Harel