Accepter le certificat ssl auto-signé du serveur dans le client Java

cela ressemble à une question standard, mais je n'ai pas pu trouver des directions claires nulle part.

j'ai du code java essayant de me connecter à un serveur avec probablement un certificat auto-signé (ou expiré). Le code signale l'erreur suivante :

[HttpMethodDirector] I/O exception (javax.net.ssl.SSLHandshakeException) caught 
when processing request: sun.security.validator.ValidatorException: PKIX path 
building failed: sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target

si je comprends bien, je dois utiliser keytool et dire à java qu'il est correct d'autoriser cette connexion.

toutes les instructions pour corriger ce problème supposer Je suis parfaitement compétent avec keytool, comme

générer la clé privée pour le serveur et l'importer dans keystore

y a-t-il quelqu'un qui pourrait poster des instructions détaillées?

j'exécute unix, donc bash script serait le mieux.

Je ne sais pas si c'est important, mais code exécuté dans jboss.

164
demandé sur jww 2010-05-24 02:48:31

6 réponses

vous avez essentiellement deux options ici: Ajouter le certificat auto-signé à votre confiance JVM ou configurer votre client à

Option 1

exportez le certificat depuis votre navigateur et importez-le dans votre JVM trustststststore (pour établir une chaîne de confiance):

<JAVA_HOME>\bin\keytool -import -v -trustcacerts
-alias server-alias -file server.cer
-keystore cacerts.jks -keypass changeit
-storepass changeit 

Option 2

Désactiver La Validation Du Certificat:

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { 
    new X509TrustManager() {     
        public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
            return new X509Certificate[0];
        } 
        public void checkClientTrusted( 
            java.security.cert.X509Certificate[] certs, String authType) {
            } 
        public void checkServerTrusted( 
            java.security.cert.X509Certificate[] certs, String authType) {
        }
    } 
}; 

// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("SSL"); 
    sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
} 
// Now you can access an https URL without having the certificate in the truststore
try { 
    URL url = new URL("https://hostname/index.html"); 
} catch (MalformedURLException e) {
} 

notez que Je ne recommander l'Option #2 à tous . Désactiver le gestionnaire de confiance Bat certaines parties de SSL et vous rend vulnérable à l'homme dans les attaques du milieu. Préférez L'Option #1 ou, mieux encore, demandez au serveur d'utiliser un "vrai" certificat signé par une AC bien connue.

252
répondu Pascal Thivent 2018-01-08 23:47:40

j'ai réglé ce problème à un fournisseur de certificats qui ne fait pas partie des serveurs de confiance JVM par défaut à partir de JDK 8u74 . Le fournisseur est www.identrust.com , mais ce n'était pas le domaine auquel j'essayais de me connecter. Ce domaine a obtenu son certificat de ce fournisseur. Voir la croix de la racine de couvrir la confiance en la liste par défaut dans le JDK/JRE? -- lire quelques entrées. Voir aussi quels navigateurs et l'exploitation support des systèmes cryptons .

donc, afin de me connecter au domaine qui m'intéressait, qui avait un certificat émis à partir de identrust.com j'ai fait les étapes suivantes. En gros, je devais obtenir le identrust.com ( DST Root CA X3 ) certificat auquel la JVM doit faire confiance. J'ai pu le faire en utilisant Apache HttpComponents 4.5 comme ceci:

1: Obtenir le certificat d'indettrust au instructions de téléchargement de la chaîne de certificats . Cliquez sur le lien DST Root CA X3 .

2: sauvegardez la chaîne de caractères dans un fichier nommé "DST Root CA X3.pem". Assurez-vous d'ajouter les lignes "- - - - certificat de début-----" et "-----certificat de fin-----" dans le fichier au début et à la fin.

3: Créer un fichier java keystore, cacerts.jks avec la commande suivante:

keytool -import -v -trustcacerts -alias IdenTrust -keypass yourpassword -file dst_root_ca_x3.pem -keystore cacerts.jks -storepass yourpassword

4: copier les cacerts résultants.JKS keystore dans les ressources répertoire de votre application java/(maven).

5: utilisez le code suivant pour charger ce fichier et le joindre à Apache 4.5 HttpClient. Cela résoudra le problème pour tous les domaines qui ont des certificats émis à partir de indetrust.com util oracle inclut le certificat dans le keystore par défaut JRE.

SSLContext sslcontext = SSLContexts.custom()
        .loadTrustMaterial(new File(CalRestClient.class.getResource("/cacerts.jks").getFile()), "yourpasword".toCharArray(),
                new TrustSelfSignedStrategy())
        .build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslcontext,
        new String[] { "TLSv1" },
        null,
        SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
        .setSSLSocketFactory(sslsf)
        .build();

quand le projet construit alors les cacerts.jks sera copié dans le classpath et chargé à partir de là. Je n'ai pas, à ce stade dans le temps, test contre d'autres sites ssl, mais si le code ci-dessus "chaînes" dans ce certificat alors ils fonctionneront aussi, mais encore une fois, je ne sais pas.

référence: contexte SSL personnalisé et Comment accepter un certificat auto-signé avec une connexion Java Httpsurlc?

5
répondu K.Nicholas 2017-05-23 12:10:31

Apache HttpClient 4.5 prend en charge l'acceptation des certificats auto-signés:

SSLContext sslContext = SSLContexts.custom()
    .loadTrustMaterial(new TrustSelfSignedStrategy())
    .build();
SSLConnectionSocketFactory socketFactory =
    new SSLConnectionSocketFactory(sslContext);
Registry<ConnectionSocketFactory> reg =
    RegistryBuilder.<ConnectionSocketFactory>create()
    .register("https", socketFactory)
    .build();
HttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg);        
CloseableHttpClient httpClient = HttpClients.custom()
    .setConnectionManager(cm)
    .build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse sslResponse = httpClient.execute(httpGet);

construit une usine de socket SSL qui utilisera le TrustSelfSignedStrategy , l'enregistrera avec un gestionnaire de connexion personnalisé puis fera un GET HTTP en utilisant ce gestionnaire de connexion.

je suis d'accord avec ceux qui chantent "don't do this in production", mais il y a des cas d'utilisation pour accepter des certificats auto-signés en dehors de la production; nous les utilisons dans la production automatisée tests d'intégration, afin que nous utilisions SSL (comme en production) même si nous ne fonctionnons pas sur le matériel de production.

3
répondu spiffy 2017-11-03 17:46:05

plutôt que de définir l'usine de socket par défaut (ce qui IMO est une mauvaise chose) - yhis va juste affecter la connexion actuelle plutôt que chaque connexion SSL que vous essayez d'ouvrir:

URLConnection connection = url.openConnection();
    // JMD - this is a better way to do it that doesn't override the default SSL factory.
    if (connection instanceof HttpsURLConnection)
    {
        HttpsURLConnection conHttps = (HttpsURLConnection) connection;
        // Set up a Trust all manager
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager()
        {

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

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

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

        // Get a new SSL context
        SSLContext sc = SSLContext.getInstance("TLSv1.2");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        // Set our connection to use this SSL context, with the "Trust all" manager in place.
        conHttps.setSSLSocketFactory(sc.getSocketFactory());
        // Also force it to trust all hosts
        HostnameVerifier allHostsValid = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
        // and set the hostname verifier.
        conHttps.setHostnameVerifier(allHostsValid);
    }
InputStream stream = connection.getInputStream();
2
répondu Jon Daniel 2016-11-11 09:56:38

faites confiance à tous les certificats SSL:- Vous pouvez contourner SSL si vous voulez tester sur le serveur de test. Mais n'utilisez pas ce code pour la production.

public static class NukeSSLCerts {
protected static final String TAG = "NukeSSLCerts";

public static void nuke() {
    try {
        TrustManager[] trustAllCerts = new TrustManager[] { 
            new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    X509Certificate[] myTrustedAnchors = new X509Certificate[0];  
                    return myTrustedAnchors;
                }

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

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

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }
        });
    } catch (Exception e) { 
    }
}

}

s'il vous Plaît appelez cette fonction dans la fonction onCreate() de l'Activité ou dans votre Classe d'Application.

NukeSSLCerts.nuke();

cela peut être utilisé pour Volley dans Android.

0
répondu Ashish Saini 2017-07-04 11:48:46

si " ils " utilisent un certificat auto-signé, c'est à eux de prendre les mesures nécessaires pour rendre leur serveur utilisable. Plus précisément, cela signifie vous fournir leur certificat hors ligne d'une manière digne de confiance. Afin de les amener à le faire. Vous l'importez ensuite dans votre boutique de fiducie en utilisant le clavier décrit dans le Guide de référence JSSE. Ne pensez même pas au gestionnaire de confiance peu sûr posté ici.

EDIT au profit de la dix-sept (!) downvoters, et de nombreux commentateurs ci-dessous, qui ont manifestement pas lu ce que j'ai écrit ici, c'est pas un jeremiad contre des certificats auto-signés. Il n'y a rien de mal à utiliser correctement les certificats auto-signés . mais, la bonne façon de les mettre en œuvre est de faire livrer le certificat en toute sécurité via un hors ligne processus, plutôt que par le canal non authentifié ils vont être utilisés pour authentifier. Certes, cela est évident, non? C'est évident pour toutes les organisations conscientes de la sécurité pour lesquelles j'ai travaillé, des banques avec des milliers de succursales à mes propres entreprises. La "solution" de la base de code client de confiance tous les certificats , y compris les certificats auto-signés signés signés par absolument n'importe qui, ou n'importe quel organisme arbitaire se mettant en place comme une CA, est ipso facto non sécurisé. Il est juste de jouer à la sécurité. Il est inutile. Vous avez une conversation privée, inviolable, à l'épreuve des réponses, à l'épreuve des injections ... quelqu'un. Quiconque. Un homme dans le milieu. Imitateur. Quiconque. Vous pouvez tout aussi bien utiliser plaintext.

-3
répondu user207421 2017-06-04 09:52:24