Utiliser char Array sur une chaîne pour manipuler les mots de passe en Java?

1. Vue d'ensemble

Dans cet article, nous expliquerons pourquoi nous devrions utiliser le tableau char [] pour représenter les mots de passe au lieu de String en Java.

Veuillez noter que ce didacticiel se concentre sur les façons de manipuler les mots de passe dans la mémoire, et non sur les façons réelles de les stocker, qui sont généralement gérées dans la couche de persistance.

Nous supposons également que nous ne pouvons pas contrôler le format du mot de passe (par exemple, le mot de passe provient de l'API tierce sous la forme de la chaîne ). Bien qu'il semble évident d'utiliser un objet de type java.lang.String pour manipuler les mots de passe, il est recommandé par l'équipe Java elle-même d'utiliser char [] à la place.

Par exemple, si nous regardons le JPasswordField de javax.swing , nous pouvons voir que la méthode getText () qui retourne String est obsolète depuis Java 2 et est remplacée par la méthode getPassword () qui retourne char [] .

Alors, explorons quelques bonnes raisons pour lesquelles c'est le cas.

2. Les chaînes sont immuables

Les chaînes en Java sont immuables, ce qui signifie que nous ne pouvons pas les modifier à l'aide d'API de haut niveau. Tout changement sur un objet String produira un nouveau String , gardant l'ancien en mémoire.

Par conséquent, le mot de passe stocké dans une chaîne sera disponible en mémoire jusqu'à ce que Garbage Collector l'efface. Nous ne pouvons pas contrôler le moment où cela se produit, mais cette période peut être beaucoup plus longue que pour les objets normaux, car les chaînes sont conservées dans un pool de chaînes à des fins de réutilisation.

Par conséquent, toute personne ayant accès au vidage de la mémoire peut récupérer le mot de passe de la mémoire.

Avec un tableau char [] au lieu de String , nous pouvons explicitement effacer les données après avoir terminé le travail prévu. De cette façon, nous nous assurerons que le mot de passe est supprimé de la mémoire avant même que le garbage collection n'ait lieu.

Jetons maintenant un coup d'œil aux extraits de code, qui illustrent ce que nous venons de discuter.

Premier pour String :

System.out.print("Original String password value: "); System.out.println(stringPassword); System.out.println("Original String password hashCode: " + Integer.toHexString(stringPassword.hashCode())); String newString = "********"; stringPassword.replace(stringPassword, newString); System.out.print("String password value after trying to replace it: "); System.out.println(stringPassword); System.out.println( "hashCode after trying to replace the original String: " + Integer.toHexString(stringPassword.hashCode()));

La sortie sera:

Original String password value: password Original String password hashCode: 4889ba9b String value after trying to replace it: password hashCode after trying to replace the original String: 4889ba9b

Maintenant pour char [] :

char[] charPassword = new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}; System.out.print("Original char password value: "); System.out.println(charPassword); System.out.println( "Original char password hashCode: " + Integer.toHexString(charPassword.hashCode())); Arrays.fill(charPassword, '*'); System.out.print("Changed char password value: "); System.out.println(charPassword); System.out.println( "Changed char password hashCode: " + Integer.toHexString(charPassword.hashCode()));

La sortie est:

Original char password value: password Original char password hashCode: 7cc355be Changed char password value: ******** Changed char password hashCode: 7cc355be

Comme nous pouvons le voir, après avoir essayé de remplacer le contenu de la chaîne d' origine , la valeur reste la même et la méthode hashCode () n'a pas renvoyé une valeur différente dans la même exécution de l'application, ce qui signifie que la chaîne d' origine est restée intacte.

Et pour le tableau char [] , nous avons pu modifier les données dans le même objet.

3. Nous pouvons accidentellement imprimer des mots de passe

Un autre avantage de travailler avec des mots de passe dans char [] array est la prévention de l'enregistrement accidentel du mot de passe dans les consoles, les moniteurs ou d'autres endroits plus ou moins non sécurisés.

Voyons le code suivant:

String passwordString = "password"; char[] passwordArray = new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}; System.out.println("Printing String password -> " + passwordString); System.out.println("Printing char[] password -> " + passwordArray);

Avec la sortie:

Printing String password -> password Printing char[] password -> [[email protected]

On voit que le contenu lui-même est imprimé dans le premier cas, tandis que dans le second cas, les données ne sont pas si utiles, ce qui rend char [] moins vulnérable.

4. Conclusion

Dans cet article rapide, nous avons souligné plusieurs raisons pour lesquelles nous ne devrions pas utiliser String s pour collecter les mots de passe et pourquoi nous devrions utiliser des tableaux char [] à la place.

Comme toujours, des extraits de code peuvent être trouvés sur GitHub.