2015-06-13 38 views
17

Ho implementato un client JAX-WS utilizzando ApacheCXF (v3.0.4) e tutto funziona correttamente ma il problema si presenta quando voglio utilizzare una connessione sicura (SSL/TLS) con java 8 (jdk1.8.0_25).Nome_server esteso (estensione SNI) non inviato con jdk1.8.0 ma inviato con jdk1.7.0

vedo la seguente eccezione nel log (-Djavax.net.debug = tutte):

main, handling exception: java.net.SocketException: Connection reset 
main, SEND TLSv1.2 ALERT: fatal, description = unexpected_message 
main, WRITE: TLSv1.2 Alert, length = 2 
main, Exception sending alert: java.net.SocketException: Connection reset by peer: socket write error 

Dopo un'analisi depeer ho osservato il problema è causato perché il con Java 8 il nome server (SNI) non viene inviato ma con Java 7 viene inviato e la chiamata al servizio web funziona correttamente.

Java 8 log (-Djavax.net.debug = tutte): Missing "nome_server Extension"

[...] 
Compression Methods: { 0 } 
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1} 
Extension ec_point_formats, formats: [uncompressed] 
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA 
*** 
[...] 

Java 7 log (-Djavax.net.debug = tutto) (opere): "Estensione nome_server" è impostato

[...] 
Compression Methods: { 0 } 
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1} 
Extension ec_point_formats, formats: [uncompressed] 
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA 
Extension server_name, server_name: [host_name: testeo.hostname.es] 
*** 
[...] 

si osserva che con Java 7 il estensione nome_server, nome_server: [HOST_NAME: testeo.hostname.es] è impostato e poi il web s ervice invocation funziona con successo.

Perché Java 8 non ha impostato il nome_server come ha fatto Java 7? È un problema di configurazione Java?

+0

Benvenuti in Stack Overflow! A differenza dei siti di forum, non utilizziamo "Grazie" o "Qualsiasi aiuto apprezzato" o firme su [so]. Vedi "[Se 'Hi', 'thanks', tagline e saluti saranno rimossi dai post?] (Http://meta.stackexchange.com/questions/2950/should-hi-thanks-taglines-and-salutations-be -removed-from-posts) .Ciao, è "Grazie in anticipo", non "Grazie in anticipo". –

risposta

0

Prima di tutto, questo "server_name" è associato con l'estensione SNI (Server Name Indication). La documentazione JSSE di Java 8 ne parla here.

La documentazione include un codice di esempio che mostra come impostare i nomi dei server che vengono inviati. Il codice è per Java 8.

Tuttavia, non riesco a capire perché (apparentemente) Java 7 sta impostando il nome del server di default, e Java 8 non lo è. (Il modo più semplice per scoprirlo sarebbe utilizzare un debugger per capire come viene creato e inizializzato l'oggetto motore SSL.)

+0

Ho riscontrato un problema simile con java7 che non lo impostava in alcuni casi e lo impostavo in altri. – CasualT

6

Si, o le librerie sottostanti (la libreria WS lo fa) potrebbero utilizzare setHostnameVerifier (..)

C'è un bug in java8, dove se viene utilizzato setHostnameVerifier (..) l'SNI non viene eseguito dal lato client.

https://bugs.openjdk.java.net/browse/JDK-8072464

12

Come detto, la causa è legata al bug JDK in cui utilizzando setHostnameVerifier() rompe SNI (Estensione nome server). https://bugs.openjdk.java.net/browse/JDK-8144566

La nostra soluzione: Dopo le prove abbiamo scoperto che l'impostazione SSLSocketFactory di una connessione a qualsiasi cosa dal default sembra per risolvere il problema.

Questo non funziona: HttpsURLConnection.setSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault());

Questo funziona: HttpsURLConnection.setSSLSocketFactory(new SSLSocketFactoryFacade());

Così, per risolvere il problema per un cliente JAX-WS, si potrebbe fare qualcosa di simile: bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", new SSLSocketFactoryFacade());

La nostra facciata SSLSocketFactory: (Si noti che in realtà non fa nulla)

public class SSLSocketFactoryFacade extends SSLSocketFactory { 

    SSLSocketFactory sslsf; 

    public SSLSocketFactoryFacade() { 
     sslsf = (SSLSocketFactory) SSLSocketFactory.getDefault();; 
    } 

    @Override 
    public String[] getDefaultCipherSuites() { 
     return sslsf.getDefaultCipherSuites(); 
    } 

    @Override 
    public String[] getSupportedCipherSuites() { 
     return sslsf.getSupportedCipherSuites(); 
    } 

    @Override 
    public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException { 
     return sslsf.createSocket(socket, s, i, b); 
    } 

    @Override 
    public Socket createSocket(String s, int i) throws IOException, UnknownHostException { 
     return sslsf.createSocket(s, i); 
    } 

    @Override 
    public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException { 
     return sslsf.createSocket(s, i, inetAddress, i1); 
    } 

    @Override 
    public Socket createSocket(InetAddress inetAddress, int i) throws IOException { 
     return createSocket(inetAddress, i); 
    } 

    @Override 
    public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException { 
     return createSocket(inetAddress, i, inetAddress1, i1); 
    } 
} 
+0

Spiegare cos'è un bindingProvider e/o aggiungere il codice per dimostrare. Vorrei usare la soluzione nel tentativo di correggere questo bug in un sistema esistente – chrisinmtown

+0

Questo trucco di classe di facciata ha corretto la mia applicazione in JDK8 insieme al nome host personalizzato. non era in grado di utilizzare un verificatore personalizzato. – Whome

+0

Avevo un'eccezione: "BuilderException: impossibile trovare il percorso di certificazione valido per la destinazione richiesta" ogni volta che riavviavo il PC e avviavo Tomcat con l'applicazione client. Dopo aver riavviato Tomcat funzionava tutto. Entrando nei registri ho scoperto che per qualche motivo l'estensione nome_server non era presente in ClientHello durante la prima esecuzione. Il custom SSLSocketFactoryFacade ha risolto il problema. L'annotazione @Delegate di BTW Lombok renderà la classe super piccola. – Yuriy

3

Utilizzare la versione JDK 8u141 e versioni successive in cui è stato risolto il problema. Per ulteriori dettagli, consultare la pagina JDK 8u141 Bugs Fixes