Dans Swing, le champ mot de passe a une getPassword()
(retourne char[]
) au lieu de la méthode getText()
( getText()
Ssortingng
) habituelle. De même, je suis tombé sur une suggestion de ne pas utiliser Ssortingng
pour gérer les mots de passe.
Pourquoi Ssortingng
constitue-t-il une menace pour la sécurité en matière de mots de passe? Il est gênant d’utiliser le char[]
.
Les chaînes sont immuables . Cela signifie qu’une fois que vous avez créé la Ssortingng
, si un autre processus peut vider la mémoire, il n’y a aucun moyen (hormis la reflection ) de vous débarrasser des données avant que la récupération de mémoire ne démarre.
Avec un tableau, vous pouvez effacer explicitement les données une fois que vous en avez fini. Vous pouvez écraser le tableau avec tout ce que vous voulez, et le mot de passe ne sera pas présent n’importe où dans le système, même avant la récupération de la mémoire.
Donc oui, c’est un problème de sécurité – mais même l’utilisation de char[]
ne réduit que la fenêtre d’opportunité pour un attaquant, et c’est uniquement pour ce type d’attaque spécifique.
Comme indiqué dans les commentaires, il est possible que les tableaux déplacés par le récupérateur de mémoire laissent des copies parasites des données en mémoire. Je pense que cela est spécifique à l’implémentation – le ramasse-miettes peut effacer toute la mémoire au fur et à mesure, pour éviter ce genre de choses. Même si c’est le cas, il y a toujours le temps pendant lequel le caractère char[]
contient les caractères réels en tant que fenêtre d’attaque.
Bien que d’autres suggestions semblent valables, il y a une autre bonne raison. Avec Plain Ssortingng
vous avez beaucoup plus de chances d’ imprimer accidentellement le mot de passe sur les journaux , les moniteurs ou tout autre endroit non sécurisé. char[]
est moins vulnérable.
Considère ceci:
public static void main(Ssortingng[] args) { Object pw = "Password"; System.out.println("Ssortingng: " + pw); pw = "Password".toCharArray(); System.out.println("Array: " + pw); }
Impressions:
Ssortingng: Password Array: [C@5829428e
Pour citer un document officiel, le guide d’architecture de cryptographie Java dit ceci à propos des mots de passe char[]
vs. Ssortingng
(à propos du cryptage par mot de passe, mais plus généralement des mots de passe):
Il semblerait logique de collecter et de stocker le mot de passe dans un object de type
java.lang.Ssortingng
. Cependant, voici la mise en garde: LesObject
de typeSsortingng
sont immuables, c’est-à-dire qu’aucune méthode ne permet de modifier (écraser) ou de mettre à zéro le contenu d’uneSsortingng
après utilisation. Cette fonctionnalité rend les objectsSsortingng
inappropriés pour stocker des informations sensibles à la sécurité telles que les mots de passe utilisateur. Vous devez toujours collecter et stocker les informations sensibles à la sécurité dans un tableau de caractères à la place.
La ligne direcsortingce 2-2 des directives de codage sécurisé pour le langage de programmation Java, version 4.0 indique également quelque chose de similaire (même si elle est à l’origine dans le contexte de la journalisation):
Directive 2-2: Ne pas consigner des informations hautement sensibles
Certaines informations, telles que les numéros de sécurité sociale (SSN) et les mots de passe, sont très sensibles. Cette information ne doit pas être conservée plus longtemps que nécessaire ni où elle peut être vue, même par les administrateurs. Par exemple, il ne devrait pas être envoyé aux fichiers journaux et sa présence ne devrait pas être détectable lors des recherches. Certaines données transitoires peuvent être conservées dans des structures de données mutables, telles que des tableaux de caractères, et effacées immédiatement après utilisation. L’effacement des structures de données a une efficacité réduite sur les systèmes d’exécution Java classiques, car les objects sont déplacés en mémoire de manière transparente pour le programmeur.
Cette directive a également des implications pour la mise en œuvre et l’utilisation de bibliothèques de niveau inférieur qui n’ont pas de connaissance sémantique des données qu’elles traitent. Par exemple, une bibliothèque d’parsing de chaînes de bas niveau peut consigner le texte sur lequel elle fonctionne. Une application peut parsingr un SSN avec la bibliothèque. Cela crée une situation où les SSN sont disponibles pour les administrateurs ayant access aux fichiers journaux.
Les tableaux de caractères ( char[]
) peuvent être effacés après utilisation en définissant chaque caractère à zéro et les chaînes non. Si quelqu’un peut en quelque sorte voir l’image mémoire, il peut voir un mot de passe en texte brut si des chaînes sont utilisées, mais si le caractère char[]
est utilisé, après avoir purgé les données avec des 0, le mot de passe est sécurisé.
Certaines personnes croient que vous devez remplacer la mémoire utilisée pour stocker le mot de passe une fois que vous n’en avez plus besoin. Cela réduit la fenêtre de temps pendant laquelle un attaquant doit lire le mot de passe de votre système et ignore complètement le fait que l’attaquant a déjà besoin d’un access suffisant pour détourner la mémoire de la JVM. Un attaquant avec autant d’access peut attraper vos événements clés, ce qui les rend complètement inutiles (AFAIK, corrigez-moi donc si je me trompe).
Mettre à jour
Grâce aux commentaires, je dois mettre à jour ma réponse. Apparemment, il y a deux cas où cela peut append une amélioration (très) mineure de la sécurité, car cela réduit le temps pendant lequel un mot de passe peut atterrir sur le disque dur. Pourtant, je pense que c’est excessif pour la plupart des cas d’utilisation.
Si possible, la désactivation des core dumps et du fichier d’échange prendrait en charge les deux problèmes. Cependant, ils nécessiteraient des droits d’administrateur et pourraient réduire les fonctionnalités (moins de mémoire à utiliser) et la récupération de la RAM d’un système en cours d’exécution constituerait toujours un problème valable.
getPassword()
de JPasswordField qui renvoie une méthode char [] et deprecated getText()
qui renvoie le mot de passe en texte clair pour des raisons de sécurité. toSsortingng () il y a toujours un risque d’imprimer du texte brut dans le fichier journal ou la console, mais si vous utilisez Array, vous n’imprimez pas le contenu du tableau, mais son emplacement de mémoire est imprimé.
Ssortingng strPwd = "passwd"; char[] charPwd = new char[]{'p','a','s','s','w','d'}; System.out.println("Ssortingng password: " + strPwd ); System.out.println("Character password: " + charPwd );
Mot de passe de chaîne: passwd
Mot de passe du personnage: [C @ 110b2345
Réflexions finales: Bien que l’utilisation de char [] ne soit pas juste suffisante, vous devez effacer le contenu pour être plus sécurisé. Je suggère également de travailler avec un mot de passe haché ou chiffré au lieu du texte brut et de le supprimer de la mémoire dès que l’authentification est terminée.
Je ne pense pas que ce soit une suggestion valable, mais je peux au moins deviner la raison.
Je pense que la motivation est de s’assurer que vous pouvez effacer toute trace du mot de passe en mémoire rapidement et avec certitude après son utilisation. Avec un caractère char[]
vous pouvez écraser chaque élément du tableau avec un blanc ou quelque chose de sûr. Vous ne pouvez pas modifier la valeur interne d’une Ssortingng
cette manière.
Mais ce n’est pas une bonne réponse. Pourquoi ne pas simplement s’assurer qu’une référence au caractère char[]
ou à la Ssortingng
ne s’échappe pas? Ensuite, il n’y a pas de problème de sécurité. Mais le fait est que les objects Ssortingng
peuvent être intern()
en théorie et conservés en vie dans le pool constant. Je suppose que l’utilisation de char[]
interdit cette possibilité.
La réponse a déjà été donnée, mais j’aimerais partager un problème que j’ai découvert récemment avec les bibliothèques Java standard. Bien qu’ils veillent maintenant à remplacer les chaînes de mots de passe par char[]
partout (ce qui est bien sûr une bonne chose), d’autres données critiques pour la sécurité semblent être négligées quand il s’agit de les effacer de la mémoire.
Je pense par exemple à la classe PrivateKey . Envisagez un scénario dans lequel vous chargez une clé RSA privée à partir d’un fichier PKCS # 12, en l’utilisant pour effectuer certaines opérations. Maintenant, dans ce cas, le fait de sniffer le mot de passe seul ne vous sera d’aucune aide tant que l’access physique au fichier de clé sera restreint. En tant qu’attaquant, il serait préférable que vous obteniez la clé directement au lieu du mot de passe. Les informations souhaitées peuvent être divulguées, les vidages de mémoire, une session de débogueur ou des fichiers d’échange ne sont que quelques exemples.
Et comme il se trouve, rien ne vous permet d’effacer les informations privées d’une PrivateKey
de la mémoire, car il n’y a pas d’API qui vous permet d’effacer les octets qui constituent les informations correspondantes.
C’est une mauvaise situation, car ce document décrit comment cette circonstance pourrait être potentiellement exploitée.
La bibliothèque OpenSSL, par exemple, écrase les sections de mémoire critiques avant que les clés privées ne soient libérées. Comme Java est collecté, nous aurions besoin de méthodes explicites pour effacer et invalider les informations privées pour les clés Java, qui doivent être appliquées immédiatement après avoir utilisé la clé.
Comme l’affirme Jon Skeet, il n’y a pas d’autre moyen que d’utiliser la reflection.
Cependant, si la reflection est une option pour vous, vous pouvez le faire.
public static void main(Ssortingng[] args) { System.out.println("please enter a password"); // don't actually do this, this is an example only. Scanner in = new Scanner(System.in); Ssortingng password = in.nextLine(); usePassword(password); clearSsortingng(password); System.out.println("password: '" + password + "'"); } private static void usePassword(Ssortingng password) { } private static void clearSsortingng(Ssortingng password) { try { Field value = Ssortingng.class.getDeclaredField("value"); value.setAccessible(true); char[] chars = (char[]) value.get(password); Arrays.fill(chars, '*'); } catch (Exception e) { throw new AssertionError(e); } }
quand courir
please enter a password hello world password: '***********'
Remarque: si le caractère [] de la chaîne a été copié dans le cadre d’un cycle GC, il est possible que la copie précédente soit quelque part en mémoire.
Cette ancienne copie n’apparaît pas dans un vidage de tas, mais si vous avez un access direct à la mémoire brute du processus, vous pouvez le voir. En général, vous devriez éviter à quiconque d’avoir un tel access.
Edit: Revenant à cette réponse après une année de recherche sur la sécurité, je réalise que cela implique malheureusement que vous comparerez jamais des mots de passe en texte clair. S’il vous plaît ne pas. Utilisez un hachage à sens unique sécurisé avec un sel et un nombre raisonnable d’itérations . Pensez à utiliser une bibliothèque: ce genre de choses est difficile à trouver!
Réponse originale: Qu’en est-il du fait que Ssortingng.equals () utilise une évaluation de court-circuit et est donc vulnérable à une attaque de synchronisation? Cela peut être improbable, mais vous pouvez théoriquement chronométrer la comparaison de mot de passe afin de déterminer la séquence de caractères correcte.
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof Ssortingng) { Ssortingng anotherSsortingng = (Ssortingng)anObject; int n = value.length; // Quits here if Ssortingngs are different lengths. if (n == anotherSsortingng.value.length) { char v1[] = value; char v2[] = anotherSsortingng.value; int i = 0; // Quits here at first different character. while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
Quelques ressources supplémentaires sur les attaques de synchronisation:
Ce sont toutes les raisons, on devrait choisir le tableau char [] au lieu de la chaîne pour le mot de passe.
1. Comme les chaînes de caractères sont immuables en Java si vous stockez le mot de passe en texte brut, il sera disponible en mémoire jusqu’à ce que le nettoyeur de la mémoire le supprime et que Ssortingng soit utilisé dans le pool de chaînes pour la réutilisation. durée, qui constituent une menace pour la sécurité. Étant donné que quiconque a access à la mémoire vive peut trouver le mot de passe en texte clair et que c’est une autre raison, vous devez toujours utiliser un mot de passe crypté plutôt que du texte brut. Puisque les chaînes sont immuables, il est impossible de modifier le contenu des chaînes car toute modification produira une nouvelle chaîne, alors que si vous atsortingbuez la valeur [], vous pouvez toujours définir tout son élément comme vide ou zéro. Ainsi, le stockage du mot de passe dans le tableau de caractères réduit clairement le risque de sécurité lié au vol du mot de passe.
2. Java lui-même recommande d’utiliser la méthode getPassword () de JPasswordField qui renvoie une méthode char [] et deprecated getText () qui renvoie le mot de passe en texte clair pour des raisons de sécurité. Il est bon de suivre les conseils de l’équipe Java et de respecter les normes plutôt que de s’y opposer.
3. Avec Ssortingng, vous risquez toujours d’imprimer du texte en clair dans le fichier journal ou la console, mais si vous utilisez Array, vous n’imprimerez pas le contenu du tableau, mais son emplacement mémoire sera imprimé. bien que ce ne soit pas une raison réelle, mais toujours logique.
Ssortingng strPassword="Unknown"; char[] charPassword= new char[]{'U','n','k','w','o','n'}; System.out.println("Ssortingng password: " + strPassword); System.out.println("Character password: " + charPassword); Ssortingng password: Unknown Character password: [C@110b053
Référence de: http://javarevisited.blogspot.com/2012/03/why-character-array-is-better-than.html J’espère que cela vous aidera.
Il n’y a rien que char array vous donne contre Ssortingng à moins que vous ne le nettoyiez manuellement après utilisation, et personne ne l’a réellement fait. Pour moi, la préférence de char [] vs Ssortingng est un peu exagérée.
Jetez un coup d’œil à la bibliothèque Spring Security largement utilisée ici et posez-vous la question: les gars de Spring Security sont-ils incompétents ou les mots de passe char [] n’ont-ils pas beaucoup de sens? Lorsque des hackers méchants s’emparent de la mémoire vive de votre mémoire vive, assurez-vous qu’ils obtiendront tous les mots de passe, même si vous utilisez des méthodes sophistiquées pour les masquer.
Cependant, Java change tout le temps, et certaines fonctionnalités effrayantes telles que la fonction de déduplication des chaînes de Java 8 peuvent interférer avec des objects Ssortingng à votre insu. Mais c’est une conversation différente.
Ssortingngs are immutable and cannot be altered once they have been created. Creating a password as a ssortingng will leave stray references to the password on the heap or on the Ssortingng pool. Now if someone takes a heap dump of the Java process and carefully scans through he might be able to guess the passwords. Of course these non used ssortingngs will be garbage collected but that depends on when the GC kicks in.
On the other side char[] are mutable as soon as the authentication is done you can overwrite them with any character like all M’s or backslashes. Now even if someone takes a heap dump he might not be able to get the passwords which are not currently in use. This gives you more control in the sense like clearing the Object content yourself vs waiting for the GC to do it.
The short and straightforward answer would be because char[]
is mutable while Ssortingng
objects are not.
Ssortingngs
in Java are immutable objects. That is why they can’t be modified once created, and therefore the only way for their contents to be removed from memory is to have them garbage collected. It will be only then when the memory freed by the object can be overwritten, and the data will be gone.
Now garbage collection in Java doesn’t happen at any guaranteed interval. The Ssortingng
can thus persist in memory for a long time, and if a process crashes during this time, the contents of the ssortingng may end up in a memory dump or some log.
With a character array , you can read the password, finish working with it as soon as you can, and then immediately change the contents.
1) Since Ssortingngs are immutable in Java if you store the password as plain text, it will be available in memory until Garbage collector clears it and since Ssortingng is used in Ssortingng pool for reusability, there is pretty high chance that it will remain in memory for the long duration, which poses a security threat. Since anyone who has access to memory dump can find the password in clear text and that’s another reason you should always use an encrypted password than plain text. Since Ssortingngs are immutable, there are no way contents of Ssortingngs can be changed because any change will produce new Ssortingng, while if you char[] you can still set all his element as blank or zero. So Storing password in character array mitigates security risk of stealing the password.
2) Java itself recommends using getPassword() method of JPasswordField which returns a char[] and deprecated getText() method which returns password in clear text stating security reason. It’s good to follow advice from Java team and adhering to standard rather than going against it.
Ssortingng in java is immutable. So whenever a ssortingng is created, it will remain in the memory until it is garbage collected. So anyone who has access to the memory can read the value of the ssortingng.
If the value of the ssortingng is modified then it will end up creating a new ssortingng. So both the original value and the modified value stay in the memory until it is garbage collected.
With the character array, the contents of the array can be modified or erased once the purpose of the password is served. The original contents of the array will not be found in memory after it is modified and even before the garbage collection kicks in.
Because of the security concern it is better to store password as a character array.
Ssortingng is immutable and it goes to the ssortingng pool. Once written, it cannot be overwritten.
char[]
is an array which you should overwrite once you used the password and this is how it should be done:
char[] passw = request.getPassword().toCharArray() if (comparePasswords(dbPassword, passw) { allowUser = true; cleanPassword(passw); cleanPassword(dbPassword); passw=null; } private static void cleanPassword (char[] pass) { for (char ch: pass) { ch = null; } }
One scenario where the attacker could use it is a crashdump – when the JVM crashes and generates a memory dump – you will be able to see the password.
That is not necessarily a malicious external attacker. This could be a support user that has access to the server for monitoring purposes. He could peek into a crashdump and find the passwords.