2010-06-22 23 views
27

Sto provando a connettermi a uno dei miei server tramite ssl, con Java. Ho provato un sacco di opzioni qui è il mio migliore prova:CertificateException: Nessun nome corrispondente a ssl.someUrl.de trovato

ho generare un jssecacerts con lo script RACCOMANDATO: http://blogs.oracle.com/andreas/resource/InstallCert.java con il comando: java InstallCert ssl.someUrl.de changeit

dopo questo ho fatto il comando di un seconda volta:

Loading KeyStore jssecacerts... 
Opening connection to ssl.someUrl.de:443... 
Starting SSL handshake... 

No errors, certificate is already trusted 

Server sent 1 certificate(s): 

1 Subject [email protected], CN=plesk, OU=Plesk, O=Parallels, L=Hernd 
on, ST=Virginia, C=US 
    Issuer [email protected], CN=plesk, OU=Plesk, O=Parallels, L=Hernd 
on, ST=Virginia, C=US 
    sha1 f1 0d 2c 54 05 e1 32 19 a0 52 5e e1 81 6c a3 a5 83 0d dd 67 
    md5  f0 b3 be 5e 5f 6e 90 d1 bc 57 7a b2 81 ce 7d 3d 

Enter certificate to add to trusted keystore or 'q' to quit: [1] 

ho copiato il file nella directory di default e ho caricato il certificato in Java trustStore

System.setProperty("javax.net.ssl.trustStore", "C:\\Program Files (x86)\\Java\\jre6\\lib\\security\\jssecacerts"); 
System.setProperty("javax.net.ssl.trustStorePassword","changeit"); 

Allora provo a collegarlo

URL url = new URL("https://ssl.someUrl.de/"); 
URLConnection conn = url.openConnection(); 
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); 

e ottengo Errore 3a linea: (Nessun nome corrispondente ssl.someUrl.de trovato)

javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching ssl.someUrl.de found 

È questo causa del certificato predefinito di Plesk o è qualcos'altro sbagliato?

Setup: JRE 6.20, Netbeans 6.8, Windows7 64bit

risposta

39

Sembra che il certificato del server che si sta tentando di connettersi non corrisponde al suo nome host.

Quando un client HTTPS si connette a un server, verifica che il nome host nel certificato corrisponda al nome host del server. Non è sufficiente che un certificato sia affidabile, deve corrispondere anche al server con cui si desidera parlare. (Come un'analogia, anche se ti fidi di un passaporto legittimo, devi comunque controllare che sia quello per la persona con cui vuoi parlare, non solo qualsiasi passaporto di cui ti fidi sia legittimo.)

In HTTP, questo è fatto controllando che:

  • il certificato contiene un nome alternativo soggetto DNS (si tratta di un'estensione standard) voce corrispondente al nome host;

  • in caso contrario, l'ultimo CN del nome distinto del soggetto (questo è il nome principale se si desidera) corrisponde al nome host. (Vedi RFC 2818.)

E 'difficile dire che cosa il nome alternativo soggetto è senza avere il certificato (anche se, se ci si connette con il browser e controllare il suo contenuto in maggior dettaglio, si dovrebbe essere in grado di vedere . it) Il nome distinto soggetto sembra essere:

[email protected], CN=plesk, OU=Plesk, O=Parallels, L=Herndon, ST=Virginia, C=US 

(sarebbe, quindi, bisogno di essere CN = ssl.someUrl.de anziché CN = Plesk, se non si dispone di un nome alternativo soggetto con DNS: ssl.someUrl.de già, suppongo che tu non lo sia.)

Potrebbe essere possibile ignorare la verifica del nome host utilizzando HttpsURLConnection.setHostnameVerifier(..). Non dovrebbe essere troppo difficile scrivere un HostnameVerifier personalizzato che bybasses la verifica, anche se suggerirei di farlo solo quando il certificato è quello qui interessato in particolare. Dovresti essere in grado di ottenerlo usando l'argomento SSLSession e il suo metodo getPeerCertificates().

(Inoltre, non è necessario impostare il javax.net.ssl. * Proprietà il modo in cui hai fatto, dal momento che si sta utilizzando i valori di default in ogni caso.)

In alternativa, se hai il controllo sul server a cui ti stai collegando e sul suo certificato, puoi crearne un certificato che corrisponda alle regole di denominazione sopra (CN dovrebbe essere sufficiente, sebbene il nome alternativo soggetto sia un miglioramento). Se un certificato autofirmato è sufficiente per quello che chiami, assicurati che il suo nome comune (CN) sia il nome host con cui stai cercando di parlare (no l'URL completo, solo il nome host).

+0

thx l'ho fatto con HostnameVerifier. Ho solo bisogno di una connessione criptata. C'è solo un client e un server, con un indirizzo fisso: // indirizzo. – fehrlich

+1

Ricordare che * è necessario * qualche forma di verifica dell'identità della crittografia per fornire sicurezza. Altrimenti è come scambiare segreti con qualcuno che non conosci: per quanto buono sia il metodo di segretezza, questo non ti protegge davvero. – Bruno

+0

ma conosco il server e l'unico client (che è sul mio computer) e nessuno può leggere il flusso di dati. E la pagina https è protetta anche con un semplice accesso. O mi sto sbagliando? – fehrlich

3

ho trovato una buona risoluzione qui: http://www.mkyong.com/webservices/jax-ws/java-security-cert-certificateexception-no-name-matching-localhost-found/

Ma il mio problema era un po 'diverso e risolto in modo diverso.

Il servizio Web era su host remoto. https://some.remote.host/MyWebService?wsdl

Ma era disponibile solo per IP per qualsiasi client, ma il certificato è stato creato per il dominio: some.remote.host (CN = some.remote.host). E questo dominio non può essere risolto da IP perché non è presentato in DNS).

Quindi, lo stesso problema è apparso: se utilizzo IP per connettersi al servizio Web da ssl, non può essere raggiunto perché il certificato CN = some.remote.host e non è uguale al nome host che ho specificato (cioè l'IP dell'host).

L'ho risolto abbinando questo hostname con IP nel file/etc/hosts. Il problema è stato risolto.

Ma nel caso in cui il servizio Web sia ospitato sul server di app localhost, pensa, dovrebbe essere risolto come in inglese descritto nel suo articolo.

1

Il nome del server deve essere uguale al nome/cognome che si dà, mentre creare un certificato

15

In Java 8 è possibile saltare nome del server il controllo con il seguente codice:

HttpsURLConnection.setDefaultHostnameVerifier ((hostname, session) -> true); 

Tuttavia questo dovrebbe essere usato solo in fase di sviluppo!

+0

grandioso, grazie. più aiuto qui: http://www.mkyong.com/webservices/jax-ws/java-security-cert-certificateexception-no-name-matching-localhost-found/ – OhadR

7

Ho creato un metodo fixUntrustCertificate(), quindi quando ho a che fare con un dominio che non è in CA affidabili è possibile richiamare il metodo prima della richiesta. Questo codice funzionerà dopo java1.4. Questo metodo si applica a tutti gli host:

public void fixUntrustCertificate() throws KeyManagementException, NoSuchAlgorithmException{ 


     TrustManager[] trustAllCerts = new TrustManager[]{ 
      new X509TrustManager() { 
       public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
        return null; 
       } 

       public void checkClientTrusted(X509Certificate[] certs, String authType) { 
       } 

       public void checkServerTrusted(X509Certificate[] certs, String authType) { 
       } 

      } 
     }; 

     SSLContext sc = SSLContext.getInstance("SSL"); 
     sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
     HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 

     HostnameVerifier allHostsValid = new HostnameVerifier() { 
      public boolean verify(String hostname, SSLSession session) { 
       return true; 
      } 
     }; 

     // set the allTrusting verifier 
     HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); 
} 
Problemi correlati