Comment puis-je assurer la destruction d’un object Ssortingng en Java?

Un employé de mon entreprise doit modifier les données d’une firebase database SQL Server via un programme que j’ai créé. Le programme a d’abord utilisé l’authentification Windows et j’ai demandé aux administrateurs de bases de données de donner à cet utilisateur un access en écriture spécifique à ladite firebase database.

Ils n’étaient pas disposés à le faire et ont plutôt donné un access en écriture à mon compte d’utilisateur Windows.

Comme je fais confiance au gars mais pas suffisamment pour le laisser travailler 90 minutes avec ma session ouverte, je vais simplement append une invite de connexion à mon programme, demander une combinaison de nom d’utilisateur et de mot de passe et me connecter à SQL Server. Je vais me connecter et faire confiance à mon application pour le laisser faire uniquement ce dont il a besoin.

Ceci, cependant, pose un petit risque de sécurité. Le didacticiel des champs de mot de passe sur le site de Sun Oracle indique que les mots de passe doivent contenir le minimum de temps requirejs en mémoire. À cette fin, la méthode getPassword renvoie un tableau char[] que vous pouvez mettre à zéro.

Cependant, la classe DriverManager de Java n’accepte que les objects Ssortingng tant que mots de passe. Je ne pourrai donc pas me débarrasser du mot de passe dès que j’en aurai fini. Et comme mon application est par ailleurs assez faible en termes d’allocations et de mémoire, qui sait combien de temps cela va durer en mémoire? Le programme durera assez longtemps, comme indiqué ci-dessus.

Bien sûr, je ne peux pas contrôler ce que font les classes SQL Server JDBC avec mon mot de passe, mais j’espérais pouvoir contrôler ce que je fais avec mon mot de passe.

Existe-t-il un moyen infaillible de détruire / mettre à zéro un object Ssortingng avec Java? Je sais que les deux sont en quelque sorte contre le langage (la destruction des objects est non déterministe et les objects Ssortingng sont immuables), et System.gc() est en quelque sorte imprévisible, mais quand même; une idée?

Alors, voici les mauvaises nouvelles. Je suis surpris que personne ne l’ait encore mentionné. avec les éboueurs modernes, même le concept de char [] entier est cassé. que vous utilisiez un Ssortingng ou un char [], les données peuvent finir par vivre en mémoire pour savoir qui-sait-longtemps. pourquoi donc? parce que les jvm modernes utilisent des collecteurs de déchets générationnels qui, en bref, copient des objects partout . Ainsi, même si vous utilisez un caractère [], la mémoire réelle utilisée peut être copiée à différents endroits dans le tas, en laissant des copies du mot de passe partout (et aucun gc performant ne va effacer la mémoire ancienne). Ainsi, lorsque vous annulez l’instance que vous avez à la fin, vous ne mettez à zéro que la dernière version en mémoire.

longue histoire, bref, il n’y a pas de solution à l’épreuve des balles. vous devez presque faire confiance à la personne.

Je ne peux que penser à une solution utilisant la reflection. Vous pouvez utiliser la reflection pour appeler le constructeur privé qui utilise un tableau de caractères partagé:

  char[] chars = {'a', 'b', 'c'}; Constructor con = Ssortingng.class.getDeclaredConstructor(int.class, int.class, char[].class); con.setAccessible(true); Ssortingng password = con.newInstance(0, chars.length, chars); System.out.println(password); //erase it Arrays.fill(chars, '\0'); System.out.println(password); 

modifier

Pour quiconque pense que c’est une précaution ou même utile, je vous encourage à lire la réponse de Jtahlborn pour au moins une mise en garde.

Si vous devez absolument, gardez une référence WeakReference sur la chaîne et continuez à engloutir la mémoire jusqu’à ce que vous forciez la récupération de mémoire de la chaîne que vous pouvez détecter en testant si la référence faible est devenue nulle. Cela peut toujours laisser les octets dans l’espace d’adressage du processus. peut être un couple de barattes de la poubelle vous donnerait du confort? Ainsi, une fois que la référence faible de votre chaîne d’origine a été annulée, créez une autre référence faible et restaurez jusqu’à ce qu’elle soit mise à zéro, ce qui impliquerait un cycle complet de récupération de place.

en quelque sorte, je dois append LOL à cela même si ma réponse ci-dessus est entièrement grave 🙂

Vous pouvez changer la valeur du caractère interne char[] utilisant la reflection.

Vous devez faire attention à le changer avec un tableau de même longueur ou à mettre à jour le champ count . Si vous souhaitez pouvoir l’utiliser comme entrée dans un ensemble ou comme valeur dans map, vous devez recalculer le code de hachage et définir la valeur du champ hashCode .

Cela dit, le code minimal pour y parvenir est

  Ssortingng password = "password"; Field valueField = Ssortingng.class.getDeclaredField("value"); valueField.setAccessible(true); char[] chars = (char[]) valueField.get(password); chars[0] = Character.valueOf('h'); System.out.println(password); 

Je ne suis pas sûr de la classe DriverManager .
En règle générale, vous avez raison, la recommandation est de stocker le mot de passe dans des tableaux de caractères et d’ effacer explicitement la mémoire après utilisation.
L’exemple le plus courant:

 KeyStore store = KeyStore. getInstance(KeyStore, getDefaultType()) ; char[] password = new char[] {'s','e','c','r','e','t'}; store .load(is, password ); //After finished clear password!!! Arrays. fill(password, '\u0000' ) ; 

Dans le JSSE et le JCA, le design avait exactement ceci en tête. C’est pourquoi les API attendent un char[] et non une chaîne.
Puisque, comme vous le savez très bien, les chaînes de caractères sont immuables, le mot de passe est éligible pour la récupération de place future et vous ne pouvez plus le réinitialiser par la suite. Cela peut entraîner des risques de sécurité par des programmes malveillants qui surveillent les zones de mémoire.
Je ne pense pas que, dans ce cas, vous étudiez la question.
En fait, il y a une question similaire ici:
Pourquoi Driver Manager n’utilise-t-il pas des tableaux de caractères?
mais il n’y a pas de réponse claire.
Il apparaît que le concept est que le mot de passe est déjà stocké dans un fichier de propriétés (il existe déjà un constructeur DriverManager qui accepte les propriétés). Le fichier lui-même impose donc un risque plus important que le chargement du mot de passe dans une chaîne.
Ou encore, les concepteurs de l’API avaient des suppositions sur la sécurité de la machine accédant à la firebase database.
Je pense que l’option la plus sûre serait d’essayer, si possible, de voir comment DriverManager utilise le mot de passe, c’est-à-dire s’il conserve une référence interne, etc.

donc je ne pourrai pas me débarrasser du mot de passe dès que j’en aurai fini.

Pourquoi pas?

Si vous obtenez une connexion via

 Driver.getConnection 

il suffit de passer le mot de passe et de le laisser

 void loginScreen() { ... connect( new Ssortingng( passwordField.getPassword() ) ); ... } ... void connect( Ssortingng withPassword ) { connection = DriverManager.getConnection( url, user, withPassword ); ... }//<-- in this line there won't be any reference to your password anymore. 

Lorsque le contrôle revient de la méthode connect , il n'y a plus de référence pour votre mot de passe. Personne ne peut plus l'utiliser. Si vous devez créer une nouvelle session, vous devez appeler à nouveau "connect" avec un nouveau mot de passe. La référence à l'object qui contient vos informations est perdue.

Si le gestionnaire de pilotes JDBC ne tient pas la chaîne (un grand si), je ne craindrais pas de forcer sa destruction. Une machine virtuelle Java moderne exécute toujours la récupération de place assez rapidement, même avec beaucoup de mémoire disponible. La question est de savoir si le nettoyage de la mémoire est efficace “effacement sécurisé”. Je doute que ce soit. J’imagine que cela oublie simplement la référence à cet emplacement de mémoire et ne renonce à rien.

Il n’y a pas de moyen régulier de forcer le ramassage des ordures. C’est possible grâce à un appel natif mais je ne sais pas si cela fonctionnerait pour les chaînes, vu qu’elles sont regroupées.

Peut-être qu’une approche alternative aidera? Je ne suis pas familier avec SQL Server, mais dans Oracle, il est courant que l’utilisateur A possède les objects de firebase database et un ensemble de procédures stockées, et que l’utilisateur B ne possède que des permissions d’exécution sur les procédures. De cette façon, le mot de passe n’est plus vraiment un problème.

Dans votre cas, ce sera votre utilisateur qui possédera tout l’object de firebase database et les procédures stockées et votre employé aura besoin de privilèges d’exécution pour les processus stockés, ce que les administrateurs de bases de données espèrent moins.

Question interessante. Quelques googels ont révélé ceci: http://securesoftware.blogspot.com/2009/01/java-security-why-not-to-use-ssortingng.html . Selon le commentaire, cela ne changera rien.

Que se passe-t-il si vous ne stockez pas la chaîne dans une variable mais la transmettez via une nouvelle chaîne (char [])?