128 votes

Comment gérer les certificats SSL non valides avec Apache HttpClient?

Je sais, il ya beaucoup de différentes questions et à beaucoup de réponses sur ce problème... Mais je ne peux pas comprendre...

J'ai:-ubuntu 9.10-desktop-amd64 + NetBeans6.7.1 installé "comme est" hors de. rep. J'ai besoin de la connexion à certains sites sur le HTTPS. Pour cela, j'utilise Apache HttpClient.

De tutoriel que j'ai lu:

"Une fois que vous avez JSSE correctement installé, sécurisé communication HTTP sur SSL doit être comme
simple comme la plaine de la communication HTTP." Et quelques exemple:

HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.verisign.com/"); 
try { 
  httpclient.executeMethod(httpget);
  System.out.println(httpget.getStatusLine());
} finally {
  httpget.releaseConnection();
}

Maintenant, j'écris ceci:

HttpClient client = new HttpClient();

HttpMethod get = new GetMethod("https://mms.nw.ru");
//get.setDoAuthentication(true);

try {
    int status = client.executeMethod(get);
    System.out.println(status);

    BufferedInputStream is = new BufferedInputStream(get.getResponseBodyAsStream());
    int r=0;byte[] buf = new byte[10];
    while((r = is.read(buf)) > 0) {
        System.out.write(buf,0,r);
    }

} catch(Exception ex) {
    ex.printStackTrace();
}

Résultat: j'ai un ensemble d'erreurs:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1627)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:204)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:198)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:994)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:142)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:533)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:471)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:904)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1132)
        at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:643)
        at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:78)
        at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
        at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(HttpConnection.java:828)
        at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2116)
        at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
        at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
        at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
        at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
        at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
        at simpleapachehttp.Main.main(Main.java:41)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:302)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:205)
        at sun.security.validator.Validator.validate(Validator.java:235)
        at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:147)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:230)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:270)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:973)
        ... 17 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:191)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:297)
        ... 23 more

Que dois-je faire pour créer plus simple connexion SSL? (Probablement sans KeyManager et la Confiance manager etc. tout.)

161voto

Kevin Points 19613

https://mms.nw.ru utilise un certificat auto-signé qui, évidemment, n'est pas contenue dans l'ensemble par défaut des gestionnaires des fonds.

Vous aurez besoin de l'une des opérations suivantes:

  • Configurer le SSLContext avec un TrustManager qui accepte toutes les cert (voir ci-dessous)

  • Configurer le SSLContext avec un magasin de confiance qui comprend votre cert

  • Ajouter le cert pour le site de java par défaut magasin de confiance.

Voici un exemple de programme qui crée un (surtout de rien) SSL Contexte qui accepte toutes les cert:

import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class SSLTest {

    public static void main(String [] args) throws Exception {
        // configure the SSLContext with a TrustManager
        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
        SSLContext.setDefault(ctx);

        URL url = new URL("https://mms.nw.ru");
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
        conn.setHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }
        });
        System.out.println(conn.getResponseCode());
        conn.disconnect();
    }

    private static class DefaultTrustManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }
}

47voto

Pascal Thivent Points 295221

https://mms.nw.ru utilise probablement un certificat n'est pas délivré par une autorité de certification. Par conséquent, vous devez ajouter le certificat à votre confiance Java magasin de clés, comme expliqué dans l'impossibilité de trouver la validité de la certification chemin d'accès à la demande de la cible:

Lorsque vous travaillez sur un client qui fonctionne avec un serveur avec SSL activé cours d'exécution dans protocole https, vous pouvez obtenir l'erreur "impossible de trouver la validité de la certification chemin d'accès à la demande de cible " si l' serveur de certificat n'est pas délivré par l'autorité de certification, mais une auto signé ou délivré par un CMS.

Pas de panique. Tout ce que vous devez faire est de ajouter le certificat de serveur pour votre confiance Java magasin de clés si votre client est écrit en Java. Vous pourriez être vous vous demandez comment faire comme si vous ne pouvez pas accéder la machine où le serveur est installé. Il est un programme simple peut vous aider. S'il vous plaît télécharger le Java le programme et l'exécuter

% java InstallCert _web_site_hostname_

Ce programme ouvre une connexion à l'hôte spécifié et a commencé un SSL poignée de main. Il a imprimé l'exception trace de la pile de l'erreur qui s'est produit et vous montre les certificats utilisés par les le serveur. Maintenant, il vous demande d'ajouter la certificat de confiance de magasin de clés.

Si vous avez changé votre esprit, entrez "q". Si vous voulez vraiment ajouter l' certificat, entrez "1", ou d'autres numéros afin d'ajouter d'autres certificats, même un certificat d'autorité de certification, mais vous ne voulez pas le faire. Une fois que vous avez faites votre choix, le programme afficher le certificat complet et puis de l'ajouter à un KeyStore Java nommé 'jssecacerts" dans le courant de répertoire.

Pour l'utiliser dans votre programme, soit configurer JSSE de l'utiliser comme la confiance magasin ou le copier dans votre $JAVA_HOME/jre/lib/security répertoire. Si vous voulez toutes les applications Java à reconnaître le certificat de confiance et pas seulement JSSE, vous pouvez également remplacer le fichier cacerts dans ce répertoire.

Après tout cela, JSSE sera en mesure de remplir une poignée de main avec l'hôte, ce que vous pouvez vérifier en exécutant la programme à nouveau.

Pour obtenir plus de détails, vous pouvez consulter Leeland blog Non plus " impossible de trouver le valide chemin d'accès de certification à la demande de cible"

23voto

Bruno Points 47560

En plus de Pascal Thivent la bonne réponse, une autre façon est d'enregistrer le certificat de Firefox (Afficher le Certificat -> Détails -> exporter) ou openssl s_client et l'importer dans le magasin de confiance.

Vous ne devriez faire cela que si vous avez un moyen de vérifier que le certificat. À défaut, le faire la première fois que vous vous connectez, il aura au moins vous donner une erreur si le certificat change de façon inattendue sur les connexions suivantes.

Pour l'importer dans un magasin de confiance, l'utiliser:

keytool -importcert -keystore truststore.jks -file servercert.pem

Par défaut, la banque de confiance devrait être lib/security/cacerts et son mot de passe doit être changeit, voir JSSE guide de Référence pour plus de détails.

Si vous ne souhaitez pas autoriser ce certificat à l'échelle mondiale, mais seulement pour ces connexions, il est possible de créer un SSLContext pour elle:

TrustManagerFactory tmf = TrustManagerFactory
    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream("/.../truststore.jks");
ks.load(fis, null);
// or ks.load(fis, "thepassword".toCharArray());
fis.close();

tmf.init(ks);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);

Ensuite, vous devez le configurer pour le Client HTTP Apache 3.x par la mise en œuvre de l'une de ses SecureProtocolSocketFactory pour utiliser cette SSLContext. (Il y a des exemples ici).

Client HTTP Apache 4.x (à l'exception de la version la plus récente) a l'appui direct pour transmettre un SSLContext.

10voto

Bozho Points 273663

À partir de http://hc.apache.org/httpclient-3.x/sslguide.html:

Protocol.registerProtocol("https", 
new Protocol("https", new MySSLSocketFactory(), 443));
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.whatever.com/");
try {
  httpclient.executeMethod(httpget);
      System.out.println(httpget.getStatusLine());
} finally {
      httpget.releaseConnection();
}

Où MySSLSocketFactory exemple peut être trouvé ici. Il fait référence à un TrustManager, que vous pouvez modifier à faire confiance à tout (bien que vous devez prendre en compte!)

6voto

Brian M. Carr Points 762

Une fois que vous avez un Java Cert Magasin (à l'aide de la grande InstallCert classe créée ci-dessus), vous pouvez obtenir java pour l'utiliser en passant par le "javax.net.le protocole ssl.trustStore" param à java de démarrage.

Ex:

java -Djavax.net.ssl.trustStore=/path/to/jssecacerts MyClassName

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X