Les .class
fichiers Java peuvent être décompilés assez facilement. Comment puis-je protéger ma base de données si je dois utiliser les données de connexion dans le code?
Les .class
fichiers Java peuvent être décompilés assez facilement. Comment puis-je protéger ma base de données si je dois utiliser les données de connexion dans le code?
Réponses:
Ne codez jamais de mots de passe en dur dans votre code. Cela a été récemment évoqué dans le Top 25 des erreurs de programmation les plus dangereuses :
Le codage en dur d'un compte secret et d'un mot de passe dans votre logiciel est extrêmement pratique - pour les ingénieurs inverseurs qualifiés. Si le mot de passe est le même pour tous vos logiciels, chaque client devient vulnérable lorsque ce mot de passe devient inévitablement connu. Et parce que c'est codé en dur, c'est une énorme douleur à réparer.
Vous devez stocker les informations de configuration, y compris les mots de passe, dans un fichier séparé que l'application lit au démarrage. C'est le seul vrai moyen d'empêcher le mot de passe de fuir suite à la décompilation (ne le compilez jamais dans le binaire pour commencer).
Pour plus d'informations sur cette erreur courante, vous pouvez lire l'article CWE-259 . L'article contient une définition plus approfondie, des exemples et de nombreuses autres informations sur le problème.
En Java, l'un des moyens les plus simples de procéder consiste à utiliser la classe Preferences. Il est conçu pour stocker toutes sortes de paramètres de programme, dont certains peuvent inclure un nom d'utilisateur et un mot de passe.
import java.util.prefs.Preferences;
public class DemoApplication {
Preferences preferences =
Preferences.userNodeForPackage(DemoApplication.class);
public void setCredentials(String username, String password) {
preferences.put("db_username", username);
preferences.put("db_password", password);
}
public String getUsername() {
return preferences.get("db_username", null);
}
public String getPassword() {
return preferences.get("db_password", null);
}
// your code here
}
Dans le code ci-dessus, vous pouvez appeler la setCredentials
méthode après avoir affiché une boîte de dialogue demandant le nom d'utilisateur et le mot de passe. Lorsque vous devez vous connecter à la base de données, vous pouvez simplement utiliser les méthodes getUsername
et getPassword
pour récupérer les valeurs stockées. Les informations de connexion ne seront pas codées en dur dans vos binaires, la décompilation ne posera donc pas de risque de sécurité.
Remarque importante: les fichiers de préférences ne sont que des fichiers XML en texte brut. Assurez-vous de prendre les mesures appropriées pour empêcher les utilisateurs non autorisés de visualiser les fichiers bruts (autorisations UNIX, autorisations Windows, et cetera). Sous Linux, au moins, ce n'est pas un problème, car l'appel Preferences.userNodeForPackage
créera le fichier XML dans le répertoire personnel de l'utilisateur actuel, qui n'est de toute façon pas lisible par les autres utilisateurs. Sous Windows, la situation peut être différente.
Notes plus importantes: Il y a eu beaucoup de discussions dans les commentaires de cette réponse et d'autres sur ce qu'est l'architecture correcte pour cette situation. La question initiale ne mentionne pas vraiment le contexte dans lequel l'application est utilisée, je vais donc parler des deux situations auxquelles je peux penser. Le premier est le cas dans lequel la personne utilisant le programme connaît déjà (et est autorisée à connaître) les informations d'identification de la base de données. Le second est le cas dans lequel vous, le développeur, essayez de garder les informations d'identification de la base de données secrètes de la personne utilisant le programme.
Premier cas: l'utilisateur est autorisé à connaître les informations de connexion à la base de données
Dans ce cas, la solution que j'ai mentionnée ci-dessus fonctionnera. La Preference
classe Java stockera le nom d'utilisateur et le mot de passe en texte brut, mais le fichier de préférences ne sera lisible que par l'utilisateur autorisé. L'utilisateur peut simplement ouvrir le fichier XML des préférences et lire les informations de connexion, mais ce n'est pas un risque de sécurité car l'utilisateur connaissait les informations d'identification au départ.
Deuxième cas: tentative de masquer les informations de connexion de l'utilisateur
C'est le cas le plus compliqué: l'utilisateur ne doit pas connaître les informations de connexion mais doit tout de même accéder à la base de données. Dans ce cas, l'utilisateur exécutant l'application a un accès direct à la base de données, ce qui signifie que le programme doit connaître les informations de connexion à l'avance. La solution que j'ai mentionnée ci-dessus ne convient pas à ce cas. Vous pouvez stocker les informations de connexion à la base de données dans un fichier de préférences, mais l'utilisateur pourra lire ce fichier, car il en sera le propriétaire. En fait, il n'y a vraiment aucun bon moyen d'utiliser ce boîtier de manière sécurisée.
Cas correct: utilisation d'une architecture à plusieurs niveaux
La bonne façon de le faire est d'avoir une couche intermédiaire, entre votre serveur de base de données et votre application client, qui authentifie les utilisateurs individuels et permet d'effectuer un ensemble limité d'opérations. Chaque utilisateur aurait ses propres informations de connexion, mais pas pour le serveur de base de données. Les informations d'identification permettraient d'accéder à la couche intermédiaire (le niveau de logique métier) et seraient différentes pour chaque utilisateur.
Chaque utilisateur aurait son propre nom d'utilisateur et mot de passe, qui pourraient être stockés localement dans un fichier de préférences sans aucun risque de sécurité. C'est ce qu'on appelle une architecture à trois niveaux (les niveaux étant votre serveur de base de données, votre serveur de logique métier et votre application cliente). C'est plus complexe, mais c'est vraiment le moyen le plus sûr de faire ce genre de chose.
L'ordre de base des opérations est:
getInventoryList
.Notez que dans l'ensemble du processus, l'application cliente ne se connecte jamais directement à la base de données . Le niveau de logique métier reçoit une demande d'un utilisateur authentifié, traite la demande du client pour une liste d'inventaire, puis n'exécute qu'une requête SQL.
Mettez le mot de passe dans un fichier que l'application lira. N'intégrez JAMAIS de mots de passe dans un fichier source. Période.
Ruby a un module peu connu appelé DBI :: DBRC pour une telle utilisation. Je n'ai aucun doute que Java a un équivalent. Quoi qu'il en soit, il n'est pas difficile d'en écrire un.
Êtes-vous en train d'écrire une application Web? Si tel est le cas, utilisez JNDI pour le configurer en externe à l'application. Un aperçu est disponible ici :
JNDI fournit un moyen uniforme pour une application de trouver et d'accéder à des services distants sur le réseau. Le service distant peut être n'importe quel service d'entreprise, y compris un service de messagerie ou un service spécifique à une application, mais, bien entendu, une application JDBC s'intéresse principalement à un service de base de données. Une fois qu'un objet DataSource est créé et enregistré auprès d'un service de dénomination JNDI, une application peut utiliser l'API JNDI pour accéder à cet objet DataSource, qui peut ensuite être utilisé pour se connecter à la source de données qu'il représente.
Quoi que vous fassiez, les informations sensibles seront stockées dans un fichier quelque part. Votre objectif est de le rendre aussi difficile que possible. Ce que vous pouvez réaliser dépend de votre projet, des besoins et de l'épaisseur du portefeuille de votre entreprise.
Le meilleur moyen est de ne stocker aucun mot de passe nulle part. Ceci est réalisé en utilisant des fonctions de hachage pour générer et stocker des hachages de mot de passe:
hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366
Les algorithmes de hachage sont des fonctions à sens unique. Ils transforment toute quantité de données en une «empreinte digitale» de longueur fixe qui ne peut pas être inversée. Ils ont également la propriété que si l'entrée change d'un tout petit peu, le hachage résultant est complètement différent (voir l'exemple ci-dessus). C'est idéal pour protéger les mots de passe, car nous voulons stocker les mots de passe sous une forme qui les protège même si le fichier de mots de passe lui-même est compromis, mais en même temps, nous devons être en mesure de vérifier que le mot de passe d'un utilisateur est correct.
Remarque sans rapport: dans l'ancien temps d'Internet, lorsque vous cliquez sur le lien «J'ai oublié mon mot de passe», les sites Web vous envoyaient par e-mail votre mot de passe en texte brut. Ils les stockaient probablement dans une base de données quelque part. Lorsque les pirates avaient accès à leur base de données, ils avaient accès à tous les mots de passe. Étant donné que de nombreux utilisateurs utilisaient le même mot de passe sur plusieurs sites Web, il s'agissait d'un énorme problème de sécurité. Heureusement, de nos jours, ce n'est pas la pratique courante.
Vient maintenant la question: quelle est la meilleure façon de stocker les mots de passe? Je considérerais cette solution (du service d'authentification et de gestion des utilisateurs de Stormpath) comme une sacrément idéale:
Évidemment, vous n'êtes ni Google ni une banque, c'est donc une solution exagérée pour vous. Mais vient ensuite la question: quelle est la sécurité requise pour votre projet, combien de temps et d'argent vous disposez?
Pour de nombreuses applications, bien que non recommandé, le stockage d'un mot de passe codé en dur dans le code peut être une solution suffisante. Cependant, en ajoutant facilement quelques étapes supplémentaires de sécurité à partir de la liste ci-dessus, vous pouvez rendre votre application beaucoup plus sécurisée.
Par exemple, supposons que l'étape 1 ne soit pas une solution acceptable pour votre projet. Vous ne voulez pas que les utilisateurs saisissent le mot de passe à chaque fois, ou vous ne voulez même pas / avez besoin que les utilisateurs connaissent le mot de passe. Vous avez toujours des informations sensibles quelque part et vous souhaitez les protéger. Vous avez une application simple, il n'y a pas de serveur pour stocker vos fichiers ou c'est trop compliqué pour votre projet. Votre application s'exécute sur des environnements dans lesquels il n'est pas possible de stocker des fichiers en toute sécurité. C'est l'un des pires cas, mais avec des mesures de sécurité supplémentaires, vous pouvez avoir une solution beaucoup plus sûre. Par exemple, vous pouvez stocker les informations sensibles dans un fichier et vous pouvez crypter le fichier. Vous pouvez avoir la clé privée de chiffrement codée en dur dans le code. Vous pouvez obscurcir le code, ce qui rend la tâche un peu plus difficile pour quelqu'un de le déchiffrer.ce lien . (Je tiens à vous avertir une fois de plus que ce n'est pas 100% sécurisé. Un hacker intelligent avec les bonnes connaissances et les bons outils peut pirater cela. Mais en fonction de vos exigences et besoins, cela pourrait être une solution suffisante pour vous).
Cette question montre comment stocker des mots de passe et d'autres données dans un fichier chiffré: Cryptage basé sur un mot de passe AES Java 256 bits
MD5 est un algorithme de hachage, pas un algorithme de cryptage, en bref, vous ne pouvez pas récupérer votre hachage, vous ne pouvez que comparer. Il devrait idéalement être utilisé lors du stockage des informations d'authentification de l'utilisateur et non du nom d'utilisateur et du mot de passe de la base de données. db username et pwd doivent être cryptés et conservés dans un fichier de configuration, pour faire le moins.