Pourquoi ne JPasswordField.getPassword() créer une Chaîne avec le mot de passe en elle?
Swing du JPasswordField
a la getPassword()
méthode qui retourne un tableau de char. Ma compréhension de ce que la pile peut être remis à zéro immédiatement après l'utilisation, de sorte que vous n'avez pas sensible choses traîner dans la mémoire pour longtemps. L'ancienne façon de récupérer le mot de passe à utiliser getText()
, qui renvoie un objet de type String, mais il a été abandonné.
Donc, ma question est pourquoi il est en fait utilisé par Java pendant le processus de récupération à l'aide de getPassword()
??? Pour être plus clair, j'ai été le débogage mon appli de test pour autre chose**, j'ai suivi les appels et bang... getText()
dans JPasswordField
a été appelé et, bien sûr, un bel objet de type String avec mon mot de passe a été créé et est maintenant suspendus autour de la mémoire.
L'essayer pour vous-même:
public class PasswordTest() {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPasswordField passField = new JPasswordField();
pass.addActionListener(new ActionListener() {
public ActionPerformed(ActionEvent evt) {
char[] p = passField.getPassword(); //put breakpoint
//do something with the array
}
});
frame.add(passField);
frame.setVisible(true);
frame.pack();
}
}
Question subsidiaire: est-ce 'hidden' utilisation de getText()
dangereux en aucune façon? Bien sûr dédié attaquant recevrez votre mot de passe s'il a compromis le système, je parle d'un moins dédié 😉
**Je suis tombé sur ce alors que je cherchais un moyen d'afficher certaines données sensibles sur un composant Swing sans l'aide d'un String
objet. Apparemment, il n'y a aucun moyen de le faire, sauf si je suis prêt à réécrire une partie (tous?) de l'API Swing.. on va pas se produire.
- Je doute de la réclamation que vous auriez besoin de réécrire le Swing API pour afficher les données sensibles. Pouvez-vous faire un composant personnalisé, qui s'étend JComponent et remplace paintComponent? Ensuite c'est à vous de savoir comment le texte est traité.
Vous devez vous connecter pour publier un commentaire.
Cela fonctionne pour moi, et vous aide à construire un Stringified mot de passe:
En fait, voici le Soleil de la mise en œuvre de
getPassword()
:La seule
getText
, c'est un appel àgetText(int offset, int length, Segment txt)
, qui appellegetChars(int où, int len, Segment txt)
, qui à son tour les copies des caractères directement dans leSegment
's de la mémoire tampon. Il n'y a pasStrings
créé il.Ensuite, le
Segment
's de la mémoire tampon est copié dans la valeur de retour et remis à zéro avant le retour de la méthode.En d'autres termes: Il n'y a pas de copie supplémentaire du mot de passe de traîner n'importe où. Il est parfaitement en sécurité tant que vous l'utilisez comme dirigé.
Ok, my bad... Toutes les cloches ont commencé à sonner dès que j'ai vu l'appel à getText() sans s'apercevoir qu'il a effectivement été introduit par moi avec l'Action de l'auditeur voici une stacktrace
Voici le code utilisé:
Et voici la sortie de la console:
Et pour l'appel à getPassword(), peut-être que je manque quelque chose, mais où est le Segment de la mémoire tampon de zéro? Je vois un tableau copie, mais pas zéro. Le tableau retourné doit être remis à zéro par moi-même, mais le Segment du tableau est toujours là...
Et la sortie:
(J'ai mis des points d'interrogation là parce que je ne peut pas passé des caractères non imprimables)
-M
Le Swing de la mise en œuvre est trop complexe pour vérifier à la main. Vous voulez des tests.
Ressemble à la chaîne de commande pour l' (inutile) de l'action de l'événement pour moi. Il y aura d'autre moyen de provoquer l'effet ainsi.
Vaguement moderne VM va déplacer des objets dans la mémoire de toute façon, de sorte que la compensation de la
char[]
ne fonctionne pas nécessairement.char[]
(mais vous ne savez pas si vous ne pouvez pas le supprimer), document de mise en œuvre peut réallouer de la mémoire tampon, etc., etc.Vous pouvez dire à un
JPasswordField
pour afficher les caractères en appelantfield.setEchoChar('\0')
. Il conserve le reste de la protection offerte parJPasswordField
(pas deString
s, ne pas couper/copier).Cela fonctionne pour moi.