Suggerimento Java 96: utilizzare HTTPS nel codice client Java

Se hai mai provato a implementare una comunicazione sicura tra un client Java e un server HTTPS (HyperText Transfer Protocol Secure), probabilmente hai scoperto che la java.net.URLclasse standard non supporta il protocollo HTTPS. L'implementazione lato server di tale equazione è abbastanza semplice. Quasi tutti i server Web disponibili oggi forniscono un meccanismo per la richiesta di dati, utilizzando HTTPS. Dopo aver configurato il server Web, qualsiasi browser può richiedere informazioni protette dal server semplicemente specificando HTTPS come protocollo per l'URL. Se non si dispone già di un server HTTPS configurato, è possibile testare il codice client con quasi tutte le pagine Web HTTPS su Internet. La sezione Risorse contiene un breve elenco di candidati che puoi utilizzare a tale scopo.

Dal punto di vista del client, tuttavia, la semplicità della S alla fine del familiare HTTP è ingannevole. Il browser sta effettivamente facendo una notevole quantità di lavoro dietro le quinte per garantire che nessuno abbia manomesso o monitorato le informazioni che hai richiesto. A quanto pare, l'algoritmo per eseguire la crittografia per HTTPS è brevettato da RSA Security (per almeno qualche altro mese). L'uso di tale algoritmo è stato concesso in licenza dai produttori di browser ma non è stato concesso in licenza da Sun Microsystems per essere incluso nell'implementazione della URLclasse Java standard . Di conseguenza, se si tenta di costruire un URLoggetto con una stringa che specifica HTTPS come protocollo, MalformedURLExceptionverrà lanciato a.

Fortunatamente, per soddisfare questo vincolo, la specifica Java prevede la possibilità di selezionare un gestore di flusso alternativo per la URLclasse. Tuttavia, la tecnica richiesta per l'implementazione è diversa, a seconda della macchina virtuale (VM) utilizzata. Per la VM compatibile con JDK 1.1 di Microsoft, JView, Microsoft ha concesso in licenza l'algoritmo e fornito un gestore di flusso HTTPS come parte del suo wininetpacchetto. Sun, d'altra parte, ha recentemente rilasciato JSSE (Java Secure Sockets Extension) per VM compatibili con JDK 1.2, in cui Sun ha anche concesso in licenza e fornito un gestore di flusso HTTPS. Questo articolo dimostrerà come implementare l'uso di un gestore di flusso abilitato per HTTPS, utilizzando JSSE e il wininetpacchetto Microsoft .

Macchine virtuali compatibili con JDK 1.2

La tecnica per utilizzare le VM compatibili con JDK 1.2 si basa principalmente su JSSE (Java Secure Sockets Extension) 1.0.1. Prima che questa tecnica funzioni, è necessario installare JSSE e aggiungerlo al percorso classe della VM client in questione.

Dopo aver installato JSSE, è necessario impostare una proprietà di sistema e aggiungere un nuovo provider di sicurezza Securityall'oggetto classe. Esistono diversi modi per eseguire entrambe queste operazioni, ma ai fini di questo articolo viene mostrato il metodo programmatico:

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

Dopo aver effettuato le due precedenti chiamate al metodo, MalformedURLExceptionnon verrà più lanciato chiamando il codice seguente:

 URL url = nuovo URL ("// [il tuo server]"); 

Se ti stai connettendo alla porta SSL standard, 443, hai la possibilità di aggiungere il numero di porta alla stringa dell'URL. Tuttavia, se il tuo server Web utilizza una porta non standard per il traffico SSL, dovrai aggiungere il numero di porta alla stringa dell'URL in questo modo:

 URL url = nuovo URL ("// [il tuo server]: 7002"); 

Un avvertimento di questa tecnica riguarda un URL che fa riferimento a un server che ha un certificato SSL non firmato o non valido. In tal caso, un tentativo di recuperare il flusso di input o output dall'oggetto di connessione dell'URL genererà un SSLExceptionmessaggio con il messaggio "catena di certificati server non attendibile". Se il server ha un certificato valido e firmato, non verrà generata alcuna eccezione.

URL url = nuovo URL ("// [il tuo server]"); URLConnection con = URL.openConnection (); // SSLException generata qui se il certificato del server non è valido con.getInputStream ();

L'ovvia soluzione a questo problema è ottenere certificati firmati per il tuo server. Tuttavia, uno dei seguenti URL può anche fornire una soluzione: "Java Secure Socket Extension 1.0.2 Changes" (Sun Microsystems) o forum di Sun Java Developer Connection.

Microsoft JView

A causa in parte della controversia in corso tra Microsoft e Sun sulla licenza di Java per l'uso su piattaforme Windows, la VM Microsoft JView è attualmente conforme solo a JDK 1.1. Pertanto, la tecnica sopra descritta non funzionerà per i client in esecuzione in JView, poiché JSSE richiede almeno una VM compatibile con 1.2.2. In modo abbastanza conveniente, tuttavia, Microsoft fornisce un gestore di flusso abilitato per HTTPS come parte del com.ms.net.wininetpacchetto.

È possibile impostare il gestore di flusso in un ambiente JView chiamando un singolo metodo statico sulla URLclasse:

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

Dopo aver effettuato la precedente chiamata al metodo, il file

MalformedURLException

non verrà più lanciato chiamando il codice seguente:

 URL url = nuovo URL ("// [il tuo server]"); 

Ci sono due avvertenze associate a quella tecnica. Primo, secondo la documentazione JDK, il setURLStreamHandlerFactorymetodo può essere chiamato al massimo una volta in una data VM. I successivi tentativi di chiamare quel metodo genereranno un file Error. In secondo luogo, come nel caso della soluzione VM 1.2, è necessario prestare attenzione quando si utilizza un URL che fa riferimento a un server con un certificato SSL non firmato o non valido. Come nel caso precedente, si verificano problemi quando si tenta di recuperare il flusso di input o output dall'oggetto connessione dell'URL. Tuttavia, invece di lanciare un SSLException, il gestore del flusso di Microsoft lancia uno standard IOException.

URL url = nuovo URL ("// [il tuo server]"); URLConnection con = url.openConnection (); // IOException generata qui se il certificato del server non è valido con.getInputStream ();

Ancora una volta, l'ovvia soluzione a questo problema è tentare la comunicazione HTTPS solo con i server che dispongono di un certificato valido e firmato. Tuttavia, JView offre un'altra opzione. Immediatamente prima di recuperare il flusso di input o output dall'oggetto di connessione dell'URL, è possibile chiamare setAllowUserInteraction(true)l'oggetto di connessione. Ciò farà sì che JView visualizzi un messaggio che avverte l'utente che i certificati del server non sono validi, ma gli darà la possibilità di procedere comunque. Tieni presente, tuttavia, che tali messaggi possono essere ragionevoli per un'applicazione desktop, ma la visualizzazione di finestre di dialogo sul tuo server per scopi diversi dal debug è probabilmente inaccettabile.

Nota: è anche possibile chiamare il setAllowUserInteraction()metodo nelle VM compatibili con JDK 1.2. Tuttavia, utilizzando la VM 1.2 di Sun (con la quale è stato testato questo codice), non vengono visualizzate finestre di dialogo anche quando tale proprietà è impostata su true.

URL url = nuovo URL ("// [il tuo server]"); URLConnection con = url.openConnection (); // fa sì che la VM visualizzi una finestra di dialogo durante la connessione // a server non attendibili con.setAllowUserInteraction (true); con.getInputStream ();

Il com.ms.net.wininetpacchetto sembra essere installato e posizionato sul classpath del sistema per impostazione predefinita sui sistemi Windows NT 4.0, Windows 2000 e Windows 9x. Inoltre, secondo la documentazione di Microsoft JDK, WinInetStreamHandlerFactoryè "... lo stesso gestore installato per impostazione predefinita durante l'esecuzione di applet."

Indipendenza dalla piattaforma

Sebbene entrambe le tecniche che ho descritto coprano la maggior parte delle piattaforme su cui può essere eseguito il client Java, potrebbe essere necessario eseguire il client Java su VM conformi a JDK 1.1 e JDK 1.2. "Scrivi una volta, corri ovunque", ricordi? A quanto pare, combinare queste due tecniche in modo che il gestore appropriato venga caricato a seconda della VM, è abbastanza semplice. Il codice seguente mostra un modo per farlo:

String strVendor = System.getProperty ("java.vendor"); String strVersion = System.getProperty ("java.version"); // Presume una stringa di versione del sistema nel formato: //[major”.[minor”.[release] (es. 1.2.2) Double dVersion = new Double (strVersion.substring (0, 3)); // Se stiamo lavorando in un ambiente MS, usa il gestore di flusso MS. if (-1 <strVendor.indexOf ("Microsoft")) {prova {Class clsFactory = Class.forName ("com.ms.net.wininet.WininetStreamHandlerFactory"); if (null! = clsFactory) URL.setURLStreamHandlerFactory ((URLStreamHandlerFactory) clsFactory.newInstance ()); } catch (ClassNotFoundException cfe) {throw new Exception ("Unable to load the Microsoft SSL" + "stream handler. Check classpath." + cfe.toString ());} // Se il factory del gestore di flusso è // già stato impostato con successo // assicurati che il nostro flag sia impostato e mangia la cattura dell'errore (Error err) {m_bStreamHandlerSet = true;}} // Se siamo in un normale ambiente Java, // prova a utilizzare il gestore JSSE. // NOTA: JSSE richiede 1.2 o meglio se (1.2 <= dVersion.doubleValue ()) {System.setProperty ("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol "); prova {// se abbiamo il provider JSSE disponibile, // e non è già stato // impostato, aggiungilo come nuovo provider alla 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 ("Unable to load the JSSE SSL stream handler." + "Check classpath." + cfe.toString ()); }}

E le applet?

L'esecuzione di comunicazioni basate su HTTPS dall'interno di un'applet sembra un'estensione naturale degli scenari descritti sopra. In realtà, nella maggior parte dei casi è ancora più semplice. Nelle versioni 4.0 e successive di Netscape Navigator e Internet Explorer, HTTPS è abilitato per impostazione predefinita per le rispettive VM. Pertanto, se desideri creare una connessione HTTPS dal codice dell'applet, specifica semplicemente HTTPS come protocollo durante la creazione di un'istanza della URLclasse:

 URL url = nuovo URL ("// [il tuo server]"); 

Se il browser client esegue il plug-in Java 2 di Sun, esistono ulteriori limitazioni su come utilizzare HTTPS. Una discussione completa sull'uso di HTTPS con il plug-in Java 2 è disponibile sul sito Web di Sun (vedere Risorse).

Conclusione

L'utilizzo del protocollo HTTPS tra le applicazioni può essere un modo rapido ed efficace per ottenere un ragionevole livello di sicurezza nella comunicazione. Sfortunatamente, i motivi per cui non è supportato come parte della specifica Java standard sembrano essere più legali che tecnici. Tuttavia, con l'avvento di JSSE e l'uso del com.ms.net.winintpacchetto Microsoft , la comunicazione sicura è possibile dalla maggior parte delle piattaforme con solo poche righe di codice.

Matt Towers, un eBozo auto-descritto, ha recentemente lasciato la sua posizione di sviluppo con Visio. Da allora è entrato a far parte di una startup Internet, PredictPoint.com, a Seattle, Washington, dove lavora come sviluppatore Java a tempo pieno.

Ulteriori informazioni su questo argomento

  • 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

Questa storia, "Java Tip 96: Usa HTTPS nel codice del tuo client Java" è stata originariamente pubblicata da JavaWorld.