2012-01-30 31 views
5

Tengo problemas para interactuar con un sitio HTTPS a través de Java. Mi programa usa una URL con un certificado que no es de confianza cada vez que se ejecuta el programa. Este programa debe ejecutarse en más de un sistema. Actualmente, tengo el siguiente:Aceptar certificados en Java

public class A{ 
    HostnameVerifier hv = new HostnameVerifier(){ 
     public boolean verify(String urlHostName, SSLSession session){ 
      return true; 
     }  
    }; 

    HttpsURLConnection.setDefaultHostnameVerifier(hv); 

    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 = null; 
    try { 
     sc = javax.net.ssl.SSLContext.getInstance("SSL"); 
    } catch (NoSuchAlgorithmException e) { 
     e.printStackTrace(); 
    } 
    try { 
     sc.init(null, trustAllCerts, null); 
    } catch (KeyManagementException e) { 
     e.printStackTrace(); 
    } 
    javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 
} 
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; 
     } 
} 

Con este código, puedo realizar el siguiente bien:

URL url = new URL(urlString); 
URLConnection cnx = url.openConnection(); 
cnx.connect(); 

InputStream ins = cnx.getInputStream(); 
BufferedReader in = new BufferedReader(new InputStreamReader(ins)); 
String curline; 
while((curline = in.readLine()) != null) { 
    System.out.println(curline); 
} 

Sin embargo, no puedo hacer lo siguiente:

httpClient = new HttpClient(); 
PostMethod postMethod = null; 
int intResult = 0; 
postMethod = new PostMethod(authURL); 
Enumeration emParams = authParams.propertyNames(); 
while (emParams.hasMoreElements()) { 
    String paramName = (String) emParams.nextElement(); 
    String paramValue = authParams.getProperty(paramName); 
    postMethod.addParameter(paramName, paramValue); 
} 

intResult = httpClient.executeMethod(postMethod); 
postMethod.releaseConnection(); 
ins.close(); 

Cuando executeMethod (postMethod) se ejecuta, obtengo una SSLHandshakeException, CertPathBuilderException, y así sucesivamente.

¿Qué puedo hacer para solucionar esto? Estoy pensando en aceptar el certificado o simplemente pasar por alto toda validación de certificado (ya que el programa se ejecuta internamente dentro de una red privada).

Gracias

+0

¿Está utilizando Apache HttpClient 3.x (o 4)? – Bruno

Respuesta

5

Parece que estás usando Apache HttpClient 3. Si esto es de hecho la versión 3, que necesita para construir su propia SecureProtocolSocketFactory como se explica en el Apache HttpClient 3 SSL guide. Hay un example here.

Para Apache HttpClient 4, debe ser capaz de pasar una SSLContext al constructor a la (HttpClient) SSLSocketFactory, como se describe en the answers to this question (incluyendo notas con respecto a la verificación del nombre de host).

Sin embargo, en términos generales, no siga este enfoque. De hecho, está desactivando la parte de autenticación de la conexión SSL/TLS al hacerlo, haciéndolo vulnerable a los ataques MITM.

En su lugar, debe importar explícitamente el certificado del servidor en el almacén de confianza de su cliente, como se describe en this answer.

estoy pensando de aceptar el certificado o simplemente pasar por toda la validación certificado (como el programa se ejecuta internamente dentro de una red privada ).

Lo que está diciendo es que usted está dispuesto a utilizar SSL/TLS para el cifrado sólo dentro de su red privada porque no confía en sus usuarios como para no mirar el tráfico que vaya alrededor de sus máquinas , pero también está asumiendo que estos usuarios no podrán realizar un ataque MITM. Esto no tiene mucho sentido. Si confías en ellos lo suficiente, también puedes enviar los datos en forma clara. Si no lo hace, debe implementar SSL/TLS correctamente, incluidos los pasos de autenticación (verificación de certificado y nombre de host).

+0

¡Gracias! Estaba usando Apache HttpClient 3.x, pero decidí ir con 4. Seguí tu recomendación y funcionó. Gracias de nuevo. – ms1013

1

HttpClient 4.3:

 HttpClientBuilder cb = HttpClientBuilder.create(); 
    SSLContextBuilder sslcb = new SSLContextBuilder(); 
    sslcb.loadTrustMaterial(KeyStore.getInstance(KeyStore.getDefaultType()), new TrustSelfSignedStrategy()); 
    cb.setSslcontext(sslcb.build()); 
    CloseableHttpClient httpclient = cb.build(); 
+0

¿podría explicar esto un poco? – benka

Cuestiones relacionadas