Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment puis-je protéger le nom d'utilisateur et le mot de passe MySQL contre la décompilation ?

Ne jamais coder en dur les mots de passe dans votre code. Cela a été évoqué récemment 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 rétro-ingénieurs qualifiés. Si le mot de passe est le même pour tous vos logiciels, alors chaque client devient vulnérable lorsque ce mot de passe devient inévitablement connu. Et parce que c'est codé en dur, c'est très pénible à 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 véritable moyen d'empêcher la fuite du mot de passe à la suite d'une 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 le setCredentials 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 le getUsername et getPassword méthodes pour récupérer les valeurs stockées. Les identifiants de connexion ne seront pas codés en dur dans vos fichiers binaires, de sorte que la décompilation ne posera pas de risque pour la sécurité.

Remarque importante : Les fichiers de préférences sont simplement 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, etc.). Sous Linux, au moins, ce n'est pas un problème, car appeler Preferences.userNodeForPackage créera le fichier XML dans le répertoire personnel de l'utilisateur actuel, qui est de toute façon illisible par les autres utilisateurs. Sous Windows, la situation peut être différente.

Plus de remarques importantes : Il y a eu beaucoup de discussions dans les commentaires de cette réponse et d'autres sur la bonne architecture 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 qui utilise le programme.

Premier cas :l'utilisateur est autorisé à connaître les identifiants de connexion à la base de données

Dans ce cas, la solution que j'ai mentionnée ci-dessus fonctionnera. La Preference Java class 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 d'identification de connexion, mais ce n'est pas un risque de sécurité car l'utilisateur connaissait les informations d'identification pour commencer.

Deuxième cas :tentative de masquer les identifiants de connexion à l'utilisateur

C'est le cas le plus compliqué :l'utilisateur ne doit pas connaître les informations d'identification de connexion, mais il a toujours besoin d'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 n'est pas appropriée pour ce cas. Vous pouvez stocker les identifiants de connexion à la base de données dans un fichier de préférences, mais l'utilisateur pourra lire ce fichier, puisqu'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 multiniveau

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 identifiants de connexion, mais pas pour le serveur de base de données. Les informations d'identification permettraient d'accéder à la couche intermédiaire (la couche 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 client). C'est plus complexe, mais c'est vraiment le moyen le plus sûr de faire ce genre de choses.

L'ordre de base des opérations est :

  1. Le client s'authentifie auprès du niveau de logique métier à l'aide du nom d'utilisateur/mot de passe personnel de l'utilisateur. Le nom d'utilisateur et le mot de passe sont connus de l'utilisateur et ne sont en aucun cas liés aux identifiants de connexion à la base de données.
  2. Si l'authentification réussit, le client envoie une requête au niveau de la logique métier demandant certaines informations de la base de données. Par exemple, un inventaire de produits. Notez que la demande du client n'est pas une requête SQL ; il s'agit d'un appel de procédure distante tel que getInventoryList .
  3. Le niveau logique métier se connecte à la base de données et récupère les informations demandées. Le niveau de logique métier est chargé de former une requête SQL sécurisée basée sur la demande de l'utilisateur. Tous les paramètres de la requête SQL doivent être filtrés pour empêcher les attaques par injection SQL.
  4. Le niveau de logique métier renvoie la liste d'inventaire à l'application cliente.
  5. Le client affiche la liste d'inventaire à l'utilisateur.

Notez que pendant tout le processus, l'application cliente ne se connecte jamais directement à la base de données . Le niveau logique métier reçoit une demande d'un utilisateur authentifié, traite la demande du client pour une liste d'inventaire, puis exécute une requête SQL.