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.URL
classe 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 URL
classe Java standard . Di conseguenza, se si tenta di costruire un URL
oggetto con una stringa che specifica HTTPS come protocollo, MalformedURLException
verrà lanciato a.
Fortunatamente, per soddisfare questo vincolo, la specifica Java prevede la possibilità di selezionare un gestore di flusso alternativo per la URL
classe. 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 wininet
pacchetto. 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 wininet
pacchetto 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 Security
all'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, MalformedURLException
non 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 SSLException
messaggio 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.wininet
pacchetto.
È possibile impostare il gestore di flusso in un ambiente JView chiamando un singolo metodo statico sulla URL
classe:
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 setURLStreamHandlerFactory
metodo 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.wininet
pacchetto 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 URL
classe:
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.winint
pacchetto Microsoft , la comunicazione sicura è possibile dalla maggior parte delle piattaforme con solo poche righe di codice.
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 theHttpMessage
class written by Jason Hunter, author of Java Servlet Programming (O'Reilly & Associates). Look forHttpsMessage
in the upcoming second edition of his book. If you wish to use that class as intended, you'll need to download and install thecom.oreilly.servlets
package. Thecom.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.