Pourquoi est-ce que char [] est préféré à String pour les mots de passe?

dans Swing, le champ Mot de passe a une méthode getPassword() (retourne char[] ) au lieu de la méthode habituelle getText() (retourne String ). De même, je suis tombé sur une suggestion de ne pas utiliser String pour gérer les mots de passe.

pourquoi String représente-t-il une menace pour la sécurité en ce qui concerne les mots de passe? Il est incommode d'utiliser char[] .

2965
demandé sur Rakete1111 2012-01-16 18:20:42

17 réponses

les cordes sont immuables . Cela signifie qu'une fois que vous avez créé le String , si un autre processus peut décharger la mémoire, il n'y a aucun moyen (à l'exception de réflexion ), vous pouvez vous débarrasser des données avant que collecte des ordures n'entre en jeu.

avec un tableau, vous pouvez effacer explicitement les données une fois que vous en avez fini avec elles. 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 le ramassage des ordures.

donc oui, ce est un problème de sécurité - mais même utiliser char[] réduit seulement la fenêtre d'opportunité pour un attaquant, et c'est seulement pour ce type spécifique d'attaque.

comme indiqué dans les commentaires, il est possible que les tableaux étant déplacés par le collecteur de déchets laissera des copies égarées des données dans la mémoire. Je pense qu'il s'agit d'une mise en œuvre spécifique-la collecteur d'ordures mai effacer toute mémoire comme il va, pour éviter ce genre de chose. Même si c'est le cas, il reste le temps pendant lequel le char[] contient les caractères réels comme une fenêtre d'attaque.

3795
répondu Jon Skeet 2018-04-20 17:50:27

bien que d'autres suggestions semblent ici valables, il y a une autre bonne raison. Avec le simple String vous avez beaucoup plus de chances de imprimer accidentellement le mot de passe aux journaux , moniteurs ou un autre endroit non sûr. char[] est moins vulnérable.

:

public static void main(String[] args) {
    Object pw = "Password";
    System.out.println("String: " + pw);

    pw = "Password".toCharArray();
    System.out.println("Array: " + pw);
}

Imprime:

String: Password
Array: [C@5829428e
1102
répondu Konrad Garus 2012-01-19 18:11:54

pour citer un document officiel, le Java Cryptography Architecture guide dit ceci au sujet de char[] vs. String mots de passe (à propos du cryptage basé sur le mot de passe, mais c'est plus généralement au sujet des mots de passe bien sûr):

il semblerait logique de collecter et de stocker le mot de passe dans un objet de type java.lang.String . Cependant, voici la mise en garde: Object s de type String sont immuables, i.e., il ya aucune méthode définie qui vous permet de modifier (écraser) ou de supprimer le contenu d'un String après l'utilisation. Cette caractéristique rend les objets String impropres stockage des informations sensibles en matière de sécurité telles que les mots de passe des utilisateurs. Vous devrait toujours recueillir et stocker des informations sensibles en matière de sécurité dans un Tableau char à la place.

ligne directrice 2-2 des Secure Coding Guidelines for the Java Programming Language, Version 4.0 dit aussi quelque chose de similaire (bien qu'il soit à l'origine dans le contexte de l'exploitation forestière):

ligne directrice 2-2: ne consignez pas les renseignements de nature très délicate

certaines informations, telles que les numéros de sécurité sociale (SSNs) et les mots de passe, est très sensible. Ces informations ne doivent pas être conservés pour une durée plus longue que nécessaire ni là où elle peut être vue, même par administrateur. Par exemple, il ne devrait pas être envoyé aux fichiers journaux et sa présence ne devrait pas être détectable par des recherches. Certains transitoire les données peuvent être conservées dans des structures de données mutables, telles que des tableaux de données char, et dégagé immédiatement après utilisation. La compensation des structures de données a réduit efficacité sur les systèmes D'exécution Java typiques lorsque les objets sont déplacés mémoire transparente au programmeur.

cette ligne directrice a également des répercussions sur la mise en oeuvre et l'utilisation des niveau inférieur bibliothèques qui n'ont pas de connaissance sémantique des données ils sont traiter avec. À titre d'exemple, un parsing de chaîne de bas niveau la bibliothèque peut enregistrer le texte. Une application peut analyser un SSN avec la bibliothèque. Cela crée une situation où les SSN sont disponible aux administrateurs ayant accès aux fichiers journaux.

625
répondu Bruno 2012-01-17 03:20:57
Les tableaux de caractères

( char[] ) peuvent être effacés après utilisation en mettant chaque caractère à zéro et les chaînes Non. Si quelqu'un peut d'une manière ou d'une Autre voir l'image mémoire, il peut voir un mot de passe en texte clair si des chaînes sont utilisées, mais si char[] est utilisé, après avoir purgé des données avec des 0, le mot de passe est sécurisé.

311
répondu alephx 2012-03-10 17:50:52

certaines personnes pensent que vous devez écraser 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 qu'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 accès suffisant pour détourner la mémoire JVM pour le faire. Un attaquant avec autant d'accès peut attraper vos événements clés rendant cela complètement inutile (AFAIK, alors s'il vous plaît corrigez-moi si je me trompe).

mise à Jour

Merci aux commentaires, je dois mettre à jour ma réponse. Apparemment, il y a deux cas où cela peut ajouter une (très) légère amélioration de la sécurité car cela réduit le temps qu'un mot de passe pourrait atterrir sur le disque dur. Je pense quand même que c'est exagéré pour la plupart des cas d'usage.

  • votre système cible peut être mal configuré ou vous devez supposer qu'il est et vous devez être paranoïaque au sujet des décharges du noyau (peut être valide si les systèmes sont ne sont pas gérés par un administrateur).
  • votre logiciel doit être excessivement paranoïaque pour empêcher les fuites de données avec l'attaquant d'accéder au matériel - en utilisant des choses comme TrueCrypt (discontinué), VeraCrypt , ou CipherShed .

si possible, désactiver les dumps du noyau et le fichier swap réglerait les deux problèmes. Toutefois, il faudrait un administrateur droits et peut réduire la fonctionnalité (moins de mémoire à utiliser) et de tirer la RAM d'un système en cours d'exécution serait toujours une préoccupation valable.

187
répondu josefx 2015-07-19 22:52:01
  1. les chaînes sont immuables en Java si vous stockez le mot de passe en texte clair, il sera disponible en mémoire jusqu'à ce que Garbage collector l'efface Et puisque les chaînes sont utilisées dans le pool de chaînes pour la réutilisation, il y a de fortes chances qu'il reste en mémoire pour une longue durée, ce qui pose une menace pour la sécurité. Depuis n'importe qui qui a accès à la mémoire dump peut trouver le mot de passe dans le texte clair
  2. recommandation Java utilisant la méthode getPassword() de JPasswordField qui renvoie une méthode char [] et dépréciée getText() qui renvoie le mot de passe dans un texte clair indiquant la raison de sécurité.
  3. toString () il y a toujours un risque d'imprimer du texte en clair dans un fichier journal ou une console, mais si vous utilisez Array, vous n'imprimerez pas le contenu du tableau à la place de son emplacement de mémoire.

    String strPwd = "passwd";
    char[] charPwd = new char[]{'p','a','s','s','w','d'};
    System.out.println("String password: " + strPwd );
    System.out.println("Character password: " + charPwd );
    

    chaîne mot de passe: passwd

    caractère mot de passe: [c@110b2345

réflexions finales: bien que l'utilisation de char[] n'est pas juste assez vous avez besoin d'effacer le contenu pour être plus sûr. Je suggère également de travailler avec un mot de passe crypté ou hashé au lieu de texte simple et de le nettoyer de la mémoire dès que l'authentification est terminée.

121
répondu Srujan Kumar Gulla 2017-06-06 08:26:12

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 dans la mémoire rapidement et avec certitude après qu'il est utilisé. Avec un char[] vous pourriez écraser chaque élément du tableau avec un blanc ou quelque chose à coup sûr. Vous ne pouvez pas modifier la valeur interne d'un String de cette façon.

mais ce seul n'est pas une bonne chose réponse; Pourquoi ne pas simplement s'assurer qu'une référence au char[] ou au String ne s'échappe pas? Alors il n'y a pas de problème de sécurité. Mais la chose est que String objets peuvent être intern() ed en théorie et maintenu en vie à l'intérieur de la piscine constante. Je suppose que l'utilisation de char[] interdit cette possibilité.

74
répondu Sean Owen 2012-01-16 14:27:54

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 prennent maintenant grand soin de 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 lorsqu'il s'agit de les effacer de la mémoire.

je pense par exemple à la classe PrivateKey . Imaginez un scénario où vous chargez un clé privée RSA à partir d'un fichier PKCS#12, en l'utilisant pour effectuer certaines opérations. Maintenant, dans ce cas, renifler le mot de passe seul ne vous aiderait pas beaucoup tant que l'accès physique au fichier clé est correctement restreint. En tant qu'attaquant, vous seriez beaucoup mieux si vous obteniez la clé directement au lieu du mot de passe. Les informations souhaitées peuvent être divulguées à plusieurs reprises, les dumps de base, une session de débogage ou des fichiers de pagination ne sont que quelques exemples.

Et comme il s'avère, il n'y a rien que vous permet d'Effacer les informations privées d'un PrivateKey depuis la mémoire, parce qu'il n'y a pas D'API qui vous permet d'Effacer les octets qui forment les informations correspondantes.

c'est une mauvaise situation, car ce papier décrit comment cette situation pourrait être exploitée.

la bibliothèque OpenSSL par exemple écrase les sections de mémoire critique avant de libérer les clés privées. Étant donné que Java est collecté par les ordures, nous aurions besoin des 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 l'utilisation de la clé.

60
répondu emboss 2012-01-19 19:39:47

comme le dit Jon Skeet, il n'y a pas d'autre moyen que d'utiliser la réflexion.

Toutefois, si la réflexion est une option pour vous, vous pouvez le faire.

public static void main(String[] args) {
    System.out.println("please enter a password");
    // don't actually do this, this is an example only.
    Scanner in = new Scanner(System.in);
    String password = in.nextLine();
    usePassword(password);

    clearString(password);

    System.out.println("password: '" + password + "'");
}

private static void usePassword(String password) {

}

private static void clearString(String password) {
    try {
        Field value = String.class.getDeclaredField("value");
        value.setAccessible(true);
        char[] chars = (char[]) value.get(password);
        Arrays.fill(chars, '*');
    } catch (Exception e) {
        throw new AssertionError(e);
    }
}

quand la course

please enter a password
hello world
password: '***********'

Note: si le char[] de la chaîne a été copié dans le cadre d'un cycle GC, il y a une chance que la copie précédente soit quelque part en mémoire.

cette ancienne copie n'apparaîtrait pas dans un tas de dump, mais si vous avez un accès direct à la mémoire brute du processus, vous pouviez le voir. En général, vous devez éviter toute personne ayant un tel accès.

42
répondu Peter Lawrey 2015-07-08 09:34:03

Edit: pour revenir à cette réponse après une année de recherche de sécurité, je me rends compte qu'il fait l'implication plutôt regrettable que vous jamais réellement comparer les mots de passe en clair. S'il te plaît, non. utilisez un hash unidirectionnel sécurisé avec un sel et un nombre raisonnable d'itérations . Pensez à utiliser une bibliothèque: ce genre de choses est difficile à obtenir droite!

réponse originale: Qu'en est-il du fait que Chaîne.equals() utilise court-circuit d'évaluation , et est donc vulnérable à une attaque temporelle? Il peut être peu probable, mais vous pourriez théoriquement time la comparaison de mot de passe afin de déterminer la séquence correcte de caractères.

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        // Quits here if Strings are different lengths.
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.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;
}

un peu plus de ressources sur les attaques de synchronisation:

34
répondu Graph Theory 2017-05-23 12:26:29

ce sont toutes les raisons, on devrait choisir char [] tableau au lieu de chaîne de caractères pour mot de passe.

1. puisque les chaînes de caractères sont immuables en Java si vous stockez le mot de passe en tant que texte brut, il sera disponible en mémoire jusqu'à ce que le collecteur de déchets le nettoie et puisque la chaîne de caractères est utilisée dans le pool de cordes pour la réutilisabilité, il y a de fortes chances qu'il reste en mémoire pour une longue durée, ce qui pose une menace pour la sécurité. Depuis n'importe qui qui a accès à la mémoire dump peut trouver le mot de passe dans le texte clair et c'est une autre raison, vous devriez toujours utiliser un mot de passe crypté que le texte simple. Puisque les chaînes sont immuables, il n'y a aucun moyen de modifier le contenu des chaînes, car toute modification produira une nouvelle chaîne, tandis que si vous char[] vous pouvez toujours définir tout son élément comme blanc ou zéro. Ainsi, stocker le mot de passe dans le tableau de caractères atténue clairement le risque de sécurité de voler le 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 dans un texte clair indiquant la raison de la sécurité. Il est bon de suivre les conseils de L'équipe Java et de respecter la norme plutôt que d'aller à l'encontre.

3. Avec String 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'imprimerez pas le contenu du tableau à la place de son emplacement de mémoire sont imprimés. mais pas une vraie raison, mais encore un sens.

    String strPassword="Unknown";
    char[] charPassword= new char[]{'U','n','k','w','o','n'};
    System.out.println("String password: " + strPassword);
    System.out.println("Character password: " + charPassword);

    String password: Unknown
    Character password: [C@110b053

référence de: http://javarevisited.blogspot.com/2012/03/why-character-array-is-better-than.html Espérons que cette aide.

34
répondu Human Being 2016-11-04 08:13:42

il n'y a rien que char array vous donne vs String à moins que vous ne le nettoyiez manuellement après utilisation, et je n'ai vu personne faire cela. Donc pour moi, la préférence de char[] vs String est un peu exagérée.

jetez un oeil à la largement utilisé bibliothèque de sécurité de printemps ici et demandez - vous-sont des gars de sécurité de printemps incompétents ou char[] mots de passe n'ont tout simplement pas beaucoup de sens. Quand un méchant hacker attrape videz la mémoire de votre RAM Assurez-vous qu'elle obtiendra tous les mots de passe même si vous utilisez des moyens sophistiqués pour les cacher.

cependant, Java change tout le temps, et certaines fonctionnalités effrayantes comme la fonctionnalité de de "Deduplication de chaîne de caractères de Java 8 pourraient interner des objets de chaîne à votre insu. Mais qui est différente de la conversation.

31
répondu Oleg Mikheev 2017-05-23 12:18:26
Les chaînes

sont immuables et ne peuvent pas être modifiées une fois qu'elles ont été créées. Créer un mot de passe sous forme de chaîne de caractères laissera des références égarées au mot de passe sur le tas ou sur le pool de chaînes de caractères. Maintenant, si quelqu'un prend un tas de dump du processus Java et scanne soigneusement à travers il pourrait être en mesure de deviner les mots de passe. Bien sûr, ces cordes non utilisées seront ramassées, mais cela dépend du moment où le GC entre en action.

de l'autre côté char[] sont mutables dès que l'authentification est faite, vous pouvez les écraser avec n'importe quel caractère comme tous les M ou antislashs. Maintenant, même si quelqu'un prend une décharge tas il pourrait ne pas être en mesure d'obtenir les mots de passe qui ne sont pas actuellement en usage. Cela vous donne plus de contrôle dans le sens comme nettoyer le contenu de L'objet vous-même vs attendre le GC pour le faire.

28
répondu Geek 2015-07-28 10:46:40

la réponse courte et directe serait parce que char[] est mutable tandis que String objets ne sont pas.

Strings en Java sont des objets immuables. C'est pourquoi ils ne peuvent pas être modifiés une fois créés, et donc le seul moyen pour que leur contenu soit retiré de la mémoire est de les faire ramasser. Ce ne sera que lorsque la mémoire libérée par l'objet pourra être écrasée et que les données auront disparu.

maintenant la collecte des ordures en Java n'a pas lieu à un intervalle garanti. Le String peut donc persister longtemps en mémoire, et si un processus s'écrase pendant ce temps, le contenu de la chaîne peut se retrouver dans un dump mémoire ou un log.

avec un tableau de caractères , vous pouvez lire le mot de passe, finir de travailler avec lui dès que vous le pouvez, et puis changer immédiatement le contenu.

16
répondu Pritam Banerjee 2018-01-05 23:40:12

1) Puisque les chaînes sont immuables en Java si vous stockez le mot de passe en texte clair, il sera disponible en mémoire jusqu'à ce que Garbage collector l'efface Et puisque String est utilisé dans String pool pour la réutilisabilité, il y a de fortes chances qu'il restera en mémoire pour la longue durée, ce qui pose une menace de sécurité. Depuis n'importe qui qui a accès à la mémoire dump peut trouver le mot de passe dans le texte clair et c'est une autre raison, vous devriez toujours utiliser un mot de passe crypté que le texte simple. Puisque les chaînes sont immuables, il n'y a aucun moyen que le contenu des chaînes puisse être modifié parce que n'importe quelle modification produira une nouvelle chaîne, tandis que si vous char[] vous pouvez encore définir tout son élément comme blanc ou zéro. Ainsi, stocker le mot de passe dans le tableau de caractères atténue le risque de sécurité de voler le 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 dans un texte clair en indiquant la sécurité raison. Il est bon de suivre les conseils de L'équipe Java et de respecter la norme plutôt que d'aller à l'encontre.

14
répondu Neeraj Gahlawat 2018-01-08 20:42:18
La chaîne

en java est immuable. Ainsi, chaque fois qu'une chaîne est créée, elle restera dans la mémoire jusqu'à ce qu'elle soit ramassée. Si quelqu'un qui a accès à la mémoire peut lire la valeur de la chaîne.

Si la valeur de la chaîne est modifiée alors elle finira par créer une nouvelle chaîne. Ainsi, la valeur originale et la valeur modifiée restent dans la mémoire jusqu'à ce qu'elles soient récupérées.



Avec le tableau des caractères, le contenu du tableau peut être modifié ou effacé une fois que le but du mot de passe est servi. Le contenu original du tableau ne sera pas retrouvé dans la mémoire après qu'il ait été modifié et même avant que la collecte des ordures ne commence.



En raison de la préoccupation de sécurité, il est préférable de stocker le mot de passe comme un tableau de caractères.

11
répondu Saathvik 2017-07-28 06:33:06

chaîne est immuable et il va à la piscine de cordes. Une fois écrite, elle ne peut pas être réécrite.

char[] est un tableau que vous devez écraser une fois que vous avez utilisé le mot de passe et voici comment cela doit être fait:

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;
 }
}

un scénario où l'attaquant pourrait l'utiliser est un crashdump - lorsque le JVM s'écrase et génère un dump mémoire - vous pourrez voir le mot de passe.

qui n'est pas nécessairement malveillants attaquant externe. Il peut s'agir d'un utilisateur de soutien qui a accès au serveur à des fins de surveillance. Il pourrait regarder dans un crashdump et trouver les mots de passe.

10
répondu ACV 2018-04-25 22:39:55