Introduction : Pourquoi cette question est-elle toujours d'actualité ?
Imaginez la situation : vous écrivez une application de connexion. L'utilisateur saisit un mot de passe et vous devez le vérifier. Il semble plus simple de le stocker sous forme de chaîne de caractères (String). Mais les développeurs Java expérimentés vous diront : "N'utilisez jamais String pour les mots de passe ! Utilisez char[] !". Pourquoi ?
Cette question est l'une des plus populaires sur Stack Overflow (plus de 100 000 vues). Et le problème n'est pas que String ne peut pas stocker de caractères. Le problème est plus profond : il concerne la sécurité, la gestion de la mémoire et les fuites de données. Dans cet article, nous expliquerons pourquoi char[] pour un mot de passe est une norme de sécurité, et nous montrerons avec des exemples de code comment implémenter correctement cette pratique en Java.
Si vous commencez tout juste à apprendre Java ou si vous souhaitez améliorer la sécurité de vos applications, cet article est pour vous.
Problème n°1 : L'immuabilité de String (Immutability)
La classe String en Java est immuable (immutable). Cela signifie qu'après la création d'un objet String, sa valeur ne peut pas être modifiée. Toute opération qui "modifie" la chaîne (par exemple, toUpperCase() ou replace()) crée en réalité un nouvel objet String en mémoire.
Pourquoi est-ce mauvais pour un mot de passe ? Regardons un exemple :
String password = "MySecret123";// ... utilisation du mot de passe pour vérification ...// Nous avons fini de travailler avec le mot de passepassword = null; // "nettoyage" de la référenceVous pensez avoir nettoyé la mémoire ? Non ! L'objet "MySecret123" est toujours présent en mémoire, dans ce qu'on appelle le String Pool (pool de chaînes). Le ramasse-miettes (GC) ne le supprime pas immédiatement. Il y restera jusqu'à la prochaine collecte des ordures, ou plus précisément, tant qu'il y a des références vers lui. Et même après password = null, l'objet lui-même peut rester en mémoire pendant une durée indéterminée.
Et si un attaquant obtient un dump mémoire (heap dump) de votre application ? Il pourra lire le mot de passe en clair. L'immuabilité de String rend impossible la suppression immédiate du mot de passe de la mémoire.
Problème n°2 : String Pool et fuite de mots de passe
Java optimise le travail avec les chaînes via le String Pool. Lorsque vous créez une chaîne avec un littéral (par exemple, "password"), elle est placée dans le pool. Si une autre partie du programme utilise la même chaîne, elle se réfère simplement à l'objet existant.
Imaginez maintenant que votre mot de passe soit "admin123". Ce même mot de passe pourrait être utilisé accidentellement ailleurs dans le système (par exemple, dans les logs, dans un nom de fichier ou dans la configuration). La chaîne "admin123" vit dans le pool pour toujours (du moins jusqu'à la fin de la JVM). Cela augmente la surface d'attaque.
// Code pouvant entraîner une fuiteString password = "admin123";System.out.println("Mot de passe : " + password); // Le mot de passe apparaît dans les logs// Même si ensuite password = null, la chaîne "admin123" reste dans les logs et dans le poolAvec un tableau char[], ce problème n'existe pas : vous pouvez explicitement écraser chaque élément du tableau après utilisation.
Solution : Tableau char[] et gestion manuelle de la mémoire
Le tableau de caractères char[] est un objet mutable. Vous pouvez modifier son contenu à tout moment. Le principal avantage : vous pouvez nettoyer le tableau immédiatement après que le mot de passe n'est plus nécessaire.
Voici à quoi cela ressemble en pratique :
import java.util.Arrays;
public class PasswordExample { public static void main(String[] args) { // Incorrect : String String passwordString = "MySecret123"; // ... vérification ... passwordString = null; // Le mot de passe peut encore être en mémoire // Correct : char[] char[] passwordChars = { 'M', 'y', 'S', 'e', 'c', 'r', 'e',