Astuce Java 96: utilisez HTTPS dans votre code client Java

Si vous avez déjà essayé d'implémenter une communication sécurisée entre un client Java et un serveur HTTPS (HyperText Transfer Protocol Secure), vous avez probablement découvert que la java.net.URLclasse standard ne prend pas en charge le protocole HTTPS. L'implémentation côté serveur de cette équation est assez simple. Presque tous les serveurs Web disponibles aujourd'hui fournissent un mécanisme de demande de données, en utilisant HTTPS. Une fois votre serveur Web configuré, n'importe quel navigateur peut demander des informations sécurisées à votre serveur en spécifiant simplement HTTPS comme protocole pour l'URL. Si vous n'avez pas encore configuré de serveur HTTPS, vous pouvez tester votre code client avec presque toutes les pages Web HTTPS sur Internet. La section Ressources contient une courte liste de candidats que vous pouvez utiliser à cette fin.

Du point de vue du client, cependant, la simplicité du S à la fin du HTTP familier est trompeuse. Le navigateur effectue en fait un travail considérable dans les coulisses pour s'assurer que personne n'a falsifié ou surveillé les informations que vous avez demandées. En fait, l'algorithme de cryptage pour HTTPS est breveté par RSA Security (pour au moins quelques mois de plus). L'utilisation de cet algorithme a été concédée sous licence par les fabricants de navigateurs mais n'a pas été autorisée par Sun Microsystems pour être incluse dans l' URLimplémentation standard de la classe Java . Par conséquent, si vous essayez de construire un URLobjet avec une chaîne spécifiant HTTPS comme protocole, un MalformedURLExceptionsera renvoyé.

Heureusement, pour s'adapter à cette contrainte, la spécification Java permet de sélectionner un autre gestionnaire de flux pour la URLclasse. Cependant, la technique requise pour l'implémentation est différente, selon la machine virtuelle (VM) que vous utilisez. Pour la machine virtuelle compatible JDK 1.1 de Microsoft, JView, Microsoft a autorisé l'algorithme et fourni un gestionnaire de flux HTTPS dans le cadre de son wininetpackage. Sun, d'autre part, a récemment publié l'extension Java Secure Sockets (JSSE) pour les machines virtuelles compatibles JDK 1.2, dans laquelle Sun a également concédé une licence et fourni un gestionnaire de flux HTTPS. Cet article montre comment implémenter l'utilisation d'un gestionnaire de flux compatible HTTPS, à l'aide du wininetpackage JSSE et Microsoft .

Machines virtuelles compatibles JDK 1.2

La technique d'utilisation des machines virtuelles compatibles JDK 1.2 repose principalement sur l'extension Java Secure Sockets (JSSE) 1.0.1. Avant que cette technique ne fonctionne, vous devez installer le JSSE et l'ajouter au chemin de classe de la VM cliente en question.

Après avoir installé le JSSE, vous devez définir une propriété système et ajouter un nouveau fournisseur de sécurité à l' Securityobjet de classe. Il existe plusieurs façons de faire ces deux choses, mais pour les besoins de cet article, la méthode par programmation est présentée:

System.setProperty ("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol"); Security.addProvider (nouveau com.sun.net.ssl.internal.ssl.Provider ());

Après avoir effectué les deux appels de méthode précédents, le MalformedURLExceptionne sera plus levé en appelant le code suivant:

 URL url = nouvelle URL ("// [votre serveur]"); 

Si vous vous connectez au port SSL standard, 443, vous avez la possibilité d'ajouter le numéro de port à la chaîne d'URL. Cependant, si votre serveur Web utilise un port non standard pour le trafic SSL, vous devrez ajouter le numéro de port à votre chaîne d'URL comme ceci:

 URL url = nouvelle URL ("// [votre serveur]: 7002"); 

Une mise en garde de cette technique concerne une URL qui fait référence à un serveur qui possède un certificat SSL non signé ou non valide. Dans ce cas, une tentative de récupération du flux d'entrée ou de sortie de l'objet de connexion de l'URL lancera un SSLExceptionmessage avec le message «chaîne de certificats de serveur non approuvée». Si le serveur dispose d'un certificat valide et signé, aucune exception ne sera levée.

URL url = nouvelle URL ("// [votre serveur]"); URLConnection con = URL.openConnection (); // SSLException lancée ici si le certificat du serveur n'est pas valide con.getInputStream ();

La solution évidente à ce problème consiste à obtenir des certificats signés pour votre serveur. Cependant, l'une des URL suivantes peut également fournir une solution: «Java Secure Socket Extension 1.0.2 Changes» (Sun Microsystems) ou le forum Java Developer Connection de Sun.

Microsoft JView

En raison en partie du différend en cours entre Microsoft et Sun sur la licence de Java pour une utilisation sur les plates-formes Windows, la machine virtuelle Microsoft JView est actuellement uniquement compatible JDK 1.1. Par conséquent, la technique décrite ci-dessus ne fonctionnera pas pour les clients exécutés dans JView, car JSSE nécessite au moins une machine virtuelle compatible 1.2.2. Cependant, Microsoft fournit un gestionnaire de flux compatible HTTPS dans le cadre du com.ms.net.wininetpackage.

Vous pouvez définir le gestionnaire de flux dans un environnement JView en appelant une seule méthode statique sur la URLclasse:

 URL.setURLStreamHandlerFactory (nouveau com.ms.net.wininet.WininetStreamHandlerFactory ()); 

Après avoir effectué l'appel de méthode précédent, le

MalformedURLException

ne sera plus levé en appelant le code suivant:

 URL url = nouvelle URL ("// [votre serveur]"); 

Il y a deux mises en garde associées à cette technique. Premièrement, selon la documentation JDK, la setURLStreamHandlerFactoryméthode peut être appelée au plus une fois dans une VM donnée. Les tentatives suivantes pour appeler cette méthode lèveront un Error. Deuxièmement, comme c'est le cas avec la solution 1.2 VM, vous devez être prudent lorsque vous utilisez une URL qui fait référence à un serveur avec un certificat SSL non signé ou non valide. Comme dans le cas précédent, des problèmes surviennent lorsqu'une tentative est effectuée pour récupérer le flux d'entrée ou de sortie à partir de l'objet de connexion de l'URL. Cependant, au lieu de lancer un SSLException, le gestionnaire de flux Microsoft lève une norme IOException.

URL url = nouvelle URL ("// [votre serveur]"); URLConnection con = url.openConnection (); // IOException levée ici si le certificat du serveur n'est pas valide con.getInputStream ();

Là encore, la solution évidente à ce problème est de tenter de communiquer avec HTTPS uniquement avec des serveurs disposant d'un certificat valide signé. Cependant, JView offre une autre option. Immédiatement avant de récupérer le flux d'entrée ou de sortie à partir de l'objet de connexion de l'URL, vous pouvez appeler setAllowUserInteraction(true)l'objet de connexion. Cela amènera JView à afficher un message avertissant l'utilisateur que les certificats du serveur ne sont pas valides, mais lui donnant la possibilité de continuer quand même. Gardez à l'esprit, cependant, que de tels messages peuvent être raisonnables pour une application de bureau, mais que des boîtes de dialogue apparaissent sur votre serveur pour autre chose que le débogage est probablement inacceptable.

Remarque: vous pouvez également appeler la setAllowUserInteraction()méthode dans les machines virtuelles compatibles JDK 1.2. Cependant, en utilisant la machine virtuelle 1.2 de Sun (avec laquelle ce code a été testé), aucune boîte de dialogue ne s'affiche même lorsque cette propriété est définie sur true.

URL url = nouvelle URL ("// [votre serveur]"); URLConnection con = url.openConnection (); // force la VM à afficher une boîte de dialogue lors de la connexion // à des serveurs non approuvés con.setAllowUserInteraction (true); con.getInputStream ();

Le com.ms.net.wininetpackage semble être installé et placé sur le chemin de classe système par défaut sur les systèmes Windows NT 4.0, Windows 2000 et Windows 9x. En outre, selon la documentation Microsoft JDK, WinInetStreamHandlerFactoryest "... le même gestionnaire qui est installé par défaut lors de l'exécution des applets."

Indépendance de la plateforme

Bien que ces deux techniques que j'ai décrites couvrent la plupart des plates-formes sur lesquelles votre client Java peut s'exécuter, votre client Java peut avoir besoin de s'exécuter sur des machines virtuelles compatibles JDK 1.1 et JDK 1.2. «Écrivez une fois, exécutez n'importe où», vous vous souvenez? En fait, combiner ces deux techniques pour que le gestionnaire approprié soit chargé en fonction de la machine virtuelle est assez simple. Le code suivant montre une façon de procéder:

String strVendor = System.getProperty ("java.vendor"); String strVersion = System.getProperty ("java.version"); // Suppose une chaîne de version du système de la forme: //[major circular.[minor .[release] (ex. 1.2.2) Double dVersion = new Double (strVersion.substring (0, 3)); // Si nous fonctionnons dans un environnement MS, utilisez le gestionnaire de flux MS. if (-1 <strVendor.indexOf ("Microsoft")) {essayez {Classe clsFactory = Class.forName ("com.ms.net.wininet.WininetStreamHandlerFactory"); if (null! = clsFactory) URL.setURLStreamHandlerFactory ((URLStreamHandlerFactory) clsFactory.newInstance ()); } catch (ClassNotFoundException cfe) {throw new Exception ("Impossible de charger le gestionnaire de flux Microsoft SSL" + ". Vérifiez le chemin de classe." + cfe.toString ());} // Si la fabrique de gestionnaire de flux a // déjà été définie avec succès // assurez-vous que notre drapeau est défini et mangez l'erreur catch (Error err) {m_bStreamHandlerSet = true;}} // Si nous sommes dans un environnement Java normal, // essayez d'utiliser le gestionnaire JSSE. // REMARQUE: JSSE nécessite la version 1.2 ou supérieure sinon if (1.2 <= dVersion.doubleValue ()) {System.setProperty ("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol "); try {// si nous avons le fournisseur JSSE disponible, // et qu'il n'a pas encore été // défini, ajoutez-le en tant que nouveau fournisseur à la classe Security. Classe clsFactory = Class.forName ("com.sun.net.ssl.internal.ssl.Provider"); if ((null! = clsFactory) && (null == Security.getProvider ("SunJSSE"))) Security.addProvider ((Provider) clsFactory.newInstance ());} catch (ClassNotFoundException cfe) {throw new Exception ("Impossible de charger le gestionnaire de flux SSL JSSE." + "Vérifier le chemin de classe." + cfe.toString ()); }}

Et les applets?

Effectuer une communication basée sur HTTPS à partir d'une applet semble être une extension naturelle des scénarios décrits ci-dessus. En réalité, c'est encore plus facile dans la plupart des cas. Dans les versions 4.0 et ultérieures de Netscape Navigator et d'Internet Explorer, HTTPS est activé par défaut pour leurs VM respectives. Par conséquent, si vous souhaitez créer une connexion HTTPS à partir de votre code d'applet, spécifiez simplement HTTPS comme protocole lors de la création d'une instance de la URLclasse:

 URL url = nouvelle URL ("// [votre serveur]"); 

Si le navigateur client exécute le plug-in Java 2 de Sun, il existe des limitations supplémentaires quant à l'utilisation de HTTPS. Une discussion complète sur l'utilisation de HTTPS avec le plug-in Java 2 peut être trouvée sur le site Web de Sun (voir Ressources).

Conclusion

L'utilisation du protocole HTTPS entre les applications peut être un moyen rapide et efficace d'obtenir un niveau de sécurité raisonnable dans votre communication. Malheureusement, les raisons pour lesquelles il n'est pas pris en charge dans le cadre de la spécification Java standard semblent être plus juridiques que techniques. Cependant, avec l'avènement du JSSE et l'utilisation du com.ms.net.winintpackage Microsoft , une communication sécurisée est possible à partir de la plupart des plates-formes avec seulement quelques lignes de code.

Matt Towers, un eBozo autoproclamé, a récemment quitté son poste de développement chez Visio. Il a depuis rejoint une startup Internet, PredictPoint.com, à Seattle, Washington, où il travaille en tant que développeur Java à plein temps.

En savoir plus sur ce sujet

  • The source code zip file for this article contains the platform-independent code shown above implemented in a class called HttpsMessage. HttpsMessage is intended as a subclass to the HttpMessage class written by Jason Hunter, author of Java Servlet Programming (O'Reilly & Associates). Look for HttpsMessage in the upcoming second edition of his book. If you wish to use that class as intended, you'll need to download and install the com.oreilly.servlets package. The com.oreilly.servlets package and corresponding source code can be found on Hunter's Website

    //www.servlets.com

  • You can also download the source zip file

    //images.techhive.com/downloads/idge/imported/article/jvw/2000/06/httpsmessage.zip

  • Here are a few good Webpages for testing HTTPS communication:
  • //www.verisign.com/
  • //happiness.dhs.org/
  • //www.microsoft.com
  • //www.sun.com
  • //www.ftc.gov
  • More information on the JSSE as well as the downloadable bits and installation instructions can be found on Sun's Website

    //java.sun.com/products/jsse/.

  • A description of how to use some JSSE services, including the technique described above, can be found in "Secure Networking in Java" by Jonathan Knudsen on the O'Reilly Website

    //java.oreilly.com/bite-size/java_1099.html

  • More information on WininetStreamHandlerFactory class can be found in the Microsoft JSDK documentation

    //www.microsoft.com/java/sdk/. In addition, the Microsoft knowledge base also publishes "PRBAllowing the URL class to access HTTPS in Applications"

    //support.microsoft.com/support/kb/articles/Q191/1/20.ASP

  • For more information on using HTTPS with the Java 2 plug-in, see "How HTTPS Works in Java Plug-In" on Sun's Website

    //java.sun.com/products/plugin/1.2/docs/https.html

Cette histoire, «Astuce Java 96: Utilisez HTTPS dans votre code client Java» a été publiée à l'origine par JavaWorld.