2012-04-10 14 views
6

Ho ricevuto un'eccezione nome host errata. Ho utilizzato this code (ottenuto da qualche collegamento) nel mio programma. Il mio programma funziona bene. La mia domanda è abbastanza sicura ?? (In quanto non sta convalidando catene di certificati)nome host errata eccezione

public class Host { 

    public String subscribe() throws Exception { 
     String resp = ""; 
     String urlString="https://xxx.xxx.xx.xx:8443/WebApplication3/NewServlet"; 
     URL url; 
     URLConnection urlConn; 
     DataOutputStream printout; 
     DataInputStream input; 
     String str = ""; 
     int flag=1; 

     try { 
      HostnameVerifier hv = new HostnameVerifier() { 
       public boolean verify(String urlHostName, SSLSession session) { 
        System.out.println("Warning: URL Host: " + urlHostName + " vs. " 
         + session.getPeerHost()); 
        return true; 
       } 
      }; 

      trustAllHttpsCertificates(); 
      HttpsURLConnection.setDefaultHostnameVerifier(hv); 

      url = new URL(urlString); 
      urlConn = url.openConnection(); 
      urlConn.setDoInput(true); 
      Object object; 
      urlConn.setUseCaches(false); 

      urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 
      input = new DataInputStream(urlConn.getInputStream()); 

      while (null != ((str = input.readLine()))) { 
       if (str.length() >0) { 
        str = str.trim(); 
        if(!str.equals("")) { 
         //System.out.println(str); 
         resp += str; 
        } 
       } 
      } 
      input.close(); 
     } catch (MalformedURLException mue) { 
      mue.printStackTrace(); 
     } catch(IOException ioe) { 
      ioe.printStackTrace(); 
     } 
     return resp; 
    } 

    public static class miTM implements javax.net.ssl.TrustManager, 
     javax.net.ssl.X509TrustManager { 

     public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
      return null; 
     } 

     public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) { 
      return true; 
     } 

     public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) { 
      return true; 
     } 

     public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { 
      return; 
     } 

     public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { 
      return; 
     } 
    } 

    private static void trustAllHttpsCertificates() throws Exception { 

     // Create a trust manager that does not validate certificate chains: 
     javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1]; 

     javax.net.ssl.TrustManager tm = new miTM(); 

     trustAllCerts[0] = tm; 

     javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL"); 

     sc.init(null, trustAllCerts, null); 

     javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 

    } 

} 
+2

Inserisci il tuo codice (senza righe commentate) come parte della tua domanda. – MByD

+0

@Binyamin Sharet: codice pubblicato come parte della mia domanda. – user10101

+0

> La mia domanda è abbastanza sicura?

risposta

4

Il codice in miTM disabilita effettivamente tutti i controlli di sicurezza SSL, in modo che il livello di sicurezza è piuttosto basso (si otterrà solo errori se il certificato SSL è rotto, ma si don' t ottenere errori quando il certificato non corrisponde al dominio).

Fondamentalmente, si tenta di stabilire una connessione senza alcuna sicurezza. Se è quello che vuoi, la soluzione potrebbe essere "abbastanza sicura" ma molto probabilmente la risposta è "no".

La soluzione corretta per questo tipo di problema è creare un certificato di corrispondenza per questo dominio.

Sfortunatamente, questo non è possibile quando il server HTTP utilizza "hosting virtuale" (= molti nomi di dominio mappano allo stesso indirizzo IP). La soluzione corretta per questo problema è ottenere il proprio indirizzo IP.

Se avete ancora voglia di provare una soluzione Java solo, uno sguardo a questa risposta: https://stackoverflow.com/a/3293720/34088

+0

: Ho visto anche questo link ... In realtà il mio codice appartiene a quello del link (che termina con -> tutorialid = 211) dato in quel link.SO qual'è la soluzione ?? – user10101

+0

Sbarazzarsi di 'trustAllHttpsCertificates()'. L'impostazione di 'HostnameVerifier' dovrebbe essere sufficiente. –

+0

Appena commentato la riga trustAllHttpsCertificates(); nel metodo di servizio ... semplicemente disabilitato il richiamo della funzione è sufficiente ?? – user10101

1

Ecco un modo per ripulire il codice e per rimanere protetti. Suppongo che il codice si connetta a un servizio conosciuto (trusted). Per fare in modo che lo stack SSL Java accetti la connessione anche in caso di mancata corrispondenza del nome host, il modo migliore è aggiungere il certificato del server al trust store JVM.

Per prima cosa è possibile esportare il certificato del server dal browser e salvarlo sul disco. Da Linux, è possibile utilizzare openssl s_client -connect xxx.xxx.xx.xx:8443 e copiare/analizzare il certificato del server in formato ASCII in un file di testo.

quindi importare il certificato del server in jre/lib/security/cacerts file di JKS con keytool

keytool -import -alias myservice -file servercertificate.cer 

Un'altra opzione che preferisco, per evitare la regressione quando Java è aggiornato, è quello di copiare cacerts nel proprio posto e dichiara che grazie alla javax.net.ssl.trustStore proprietà di sistema.

Poiché il certificato del server è nel trust store ... è attendibile fino alla scadenza. Questo è spesso usato per i certificati server autofirmati.

1

molte volte in Java utilizzato per ottenere questo tipo di eccezioni

problema potrebbe essere ipconflict/ip-dominio mancata corrispondenza/non valido certificato

ho risolto utilizzando il suo indirizzo IP appropriato e l'installazione di certificato.

1

per effettuare la connessione a proteggere MUST (almeno):

  • verificare che vi fidate il certificato,
  • verificare il nome host (a meno che non si sa per certo che questo è l'unico e solo certificato di cui ti fidi, forse).

Il tuo codice non riesce su questi due punti:

  • Il TrustManager si sta utilizzando non controlla il certificato a tutti (non è mai genera un'eccezione, mentre l'API si aspetta che gettare una forma di CertificateException quando il certificato non è attendibile).
  • Il verificatore del nome host restituisce sempre true.

per risolvere il tuo codice:

  • Tenere i manager di fiducia di default, oppure inizializzare con il proprio negozio di fiducia e l'impostazione predefinita TrustManagerFactory.
  • Mantiene il verificatore del nome host predefinito.

Il titolo della tua domanda ("nome host eccezione sbagliato") e il vostro esempio URL https://xxx.xxx.xx.xx:8443 sembra suggerire ci si connette a un indirizzo IP.

A differenza di alcuni browser, Java segue le specifiche (RFC 2818) piuttosto rigorosamente su questo:

Se è presente un'estensione subjectAltName di tipo dNSName, che deve essere utilizzato come l'identità. In caso contrario, DEVE essere utilizzato il (più specifico) comune campo Nome nel campo Oggetto del certificato. Anche se l'uso del nome comune è una pratica esistente, è deprecato e le autorità di certificazione sono incoraggiate ad utilizzare il dNSName .

[...]

In alcuni casi, l'URI è specificato come un indirizzo IP anziché un nome host. In questo caso, il NomeAloggettoNomeIndirizzo iP deve essere presente nel certificato e deve corrispondere esattamente all'IP nell'URI.

Ciò significa che non è possibile cavarsela semplicemente inserendo l'indirizzo IP nel Common Name (CN) del DN soggetto nel certificato del server. Se stai usando un indirizzo IP, è DEVE essere in una voce Nome soggetto alternativo. (A partire da Java 7, keytool dispone di opzioni per generare tali certificati.)

Troverete ulteriori dettagli su quali comandi utilizzare in this answer.

Detto questo, l'uso di indirizzi IP può funzionare solo al massimo in un ambiente di test. Non credo che nessuna CA commerciale ti fornirà un certificato basato sull'indirizzo IP. Suggerisco di impostare le voci DNS (anche se è solo nei file hosts in un ambiente di prova).

Anche se non si utilizza l'indirizzo IP, è necessario assicurarsi che tale certificato sia valido per il nome host con cui si sta tentando di contattare il server: se si dispone di voci Nome alternativo soggetto, uno di essi deve abbinare il nome host; in caso contrario, il nome host deve trovarsi nel RDN CN del DN soggetto del certificato.