Comment résoudre l'erreur javax.net.ssl.SSLHandshakeException?

101

Je me suis connecté avec VPN pour configurer l'API d'inventaire afin d'obtenir la liste des produits et cela fonctionne bien. Une fois que j'obtiens le résultat du service Web et que je me lie à l'interface utilisateur. Et j'ai également intégré PayPal à mon application pour effectuer un paiement express lorsque je fais un appel de paiement, je suis confronté à cette erreur. J'utilise un servlet pour le processus back-end. Quelqu'un peut-il dire comment résoudre ce problème?

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
selladurai
la source
1
ce que j'aimerais savoir, quelle cible exacte était dans ce cas ... Vous obtenez une exception, mais vous n'obtenez aucune information sur la cible, qui pourrait être différente de ce que vous attendez .. J'ai un tel cas, je suis sûr que mon lien a un certificat, et je reçois toujours cette exception
ante.sabo

Réponses:

151

Tout d'abord, vous devez obtenir le certificat public du serveur auquel vous essayez de vous connecter. Cela peut être fait de différentes manières, comme contacter l'administrateur du serveur et le demander, utiliser OpenSSL pour le télécharger ou, comme cela semble être un serveur HTTP, s'y connecter avec n'importe quel navigateur, afficher les informations de sécurité de la page. et enregistrer une copie du certificat. (Google devrait être en mesure de vous dire exactement quoi faire pour votre navigateur spécifique.)

Maintenant que vous avez enregistré le certificat dans un fichier, vous devez l'ajouter au magasin de confiance de votre JVM. A $JAVA_HOME/jre/lib/security/pour JREs ou $JAVA_HOME/lib/securitypour JDKs, il y a un fichier nommé cacerts, qui est livré avec Java et contient les certificats publics des autorités de certification bien connus. Pour importer le nouveau certificat, exécutez keytool en tant qu'utilisateur autorisé à écrire sur cacerts:

keytool -import -file <the cert file> -alias <some meaningful name> -keystore <path to cacerts file>

Il vous demandera probablement un mot de passe. Le mot de passe par défaut fourni avec Java est changeit. Presque personne ne le change. Une fois ces étapes relativement simples terminées, vous communiquerez en toute sécurité et avec l'assurance que vous parlez au bon serveur et uniquement au bon serveur (tant qu'ils ne perdent pas leur clé privée).

Ryan Stewart
la source
12
J'aurai besoin d'un peu plus de détails que "ne fonctionne pas". Essayez de mettre à jour votre question avec ce que vous avez essayé et une sortie d'erreur. Malheureusement, l'heure du coucher est bien passée, alors peut-être que quelqu'un d'autre pourra répondre à vos questions. C'est également une situation très courante. Vous pouvez trouver de nombreuses informations à ce sujet en ligne, y compris la documentation keytool .
Ryan Stewart
Fondamentalement, je dois inclure PayPal cert. J'ai fait vos étapes et j'ai également ajouté le certificat à l'emplacement approprié. alors je lance l'application, il dit la même erreur?
selladurai
En fait, cela fonctionne bien sans problème de navigateur et j'ai connecté VPN pour obtenir la liste d'inventaire à ce moment-là, j'effectue un paiement avec PayPal, c'est une erreur SSL, mais j'utilise des données hors ligne ou des données codées à chaud signifie que cela fonctionne.
selladurai
4
@selladurai: Vous ne devriez pas avoir besoin d'importer un certificat pour paypal. À moins que votre fichier cacerts n'ait été corrompu ou modifié, il devrait contenir tous les certificats racine de confiance, et le certificat de paypal devrait pouvoir être retracé jusqu'à l'un d'entre eux. Vous pouvez essayer d'obtenir une copie des cacerts que vous savez être bons et essayer celui-là à la place. Si le problème persiste, il se peut que vous ne vous connectiez pas à PayPal.
Ryan Stewart
@RyanStewart dois-je l'importer dans Glassfish d'une manière ou d'une autre? Parce que j'ai ajouté le fichier .cer à mon cacert dans mon répertoire de base java, mais glassfish ne semble pas l'utiliser, donc j'obtiens toujours l'erreur.
Ced
15

Maintenant, j'ai résolu ce problème de cette façon,

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.OutputStream; 

// Create a trust manager that does not validate certificate chains like the default 

TrustManager[] trustAllCerts = new TrustManager[]{
        new X509TrustManager() {

            public java.security.cert.X509Certificate[] getAcceptedIssuers()
            {
                return null;
            }
            public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
            {
                //No need to implement.
            }
            public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
            {
                //No need to implement.
            }
        }
};

// 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 (Exception e) 
{
    System.out.println(e);
}

Bien entendu, cette solution ne doit être utilisée que dans des scénarios où il n'est pas possible d'installer les certificats requis en utilisant keytoolpar exemple des tests locaux avec des certificats temporaires.

selladurai
la source
52
Wow, j'hésiterais à appeler cela une «solution». Vous venez de désactiver la sécurité. Oui, les données seront toujours cryptées, mais vous n'avez aucune garantie que vous parlez à qui vous vous attendez à parler. La bonne solution consiste à obtenir la clé publique de votre serveur cible et à l'importer dans le trust store de la JVM établissant la connexion.
Ryan Stewart
1
voir ma réponse pour une solution appropriée
Ryan Stewart
Exemple de quoi? Ma réponse devrait contenir toutes les étapes dont vous avez besoin.
Ryan Stewart
3
Le code présenté ici semble utile si vous écrivez un test très simple sur un serveur de développement, je ne me fierais pas à lui pour la production.
Jason D
12

Chaque fois que nous essayons de nous connecter à l'URL,

si le serveur de l'autre site fonctionne sur le protocole https et exige que nous communiquions via les informations fournies dans le certificat, nous avons l'option suivante:

1) demandez le certificat (téléchargez le certificat), importez ce certificat en trustore. Les utilisations Java de confiance par défaut peuvent être trouvées dans \ Java \ jdk1.6.0_29 \ jre \ lib \ security \ cacerts, alors si nous réessayons de nous connecter à l'URL, la connexion sera acceptée.

2) Dans les cas commerciaux normaux, nous pourrions nous connecter à des URL internes dans des organisations et nous savons qu'elles sont correctes. Dans de tels cas, vous êtes sûr qu'il s'agit de l'URL correcte. Dans les cas ci-dessus, un code peut être utilisé qui ne demandera pas de stocker le certificat pour se connecter à une URL particulière.

pour le point n ° 2, nous devons suivre les étapes ci-dessous:

1) écrivez ci-dessous la méthode qui définit HostnameVerifier pour HttpsURLConnection qui renvoie true pour tous les cas, ce qui signifie que nous faisons confiance au trustStore.

  // trusting all certificate 
 public void doTrustToCertificates() throws Exception {
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

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

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

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                if (!urlHostName.equalsIgnoreCase(session.getPeerHost())) {
                    System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
                }
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }

2) écrivez la méthode ci-dessous, qui appelle doTrustToCertificates avant d'essayer de vous connecter à l'URL

    // connecting to URL
    public void connectToUrl(){
     doTrustToCertificates();//  
     URL url = new URL("https://www.example.com");
     HttpURLConnection conn = (HttpURLConnection)url.openConnection(); 
     System.out.println("ResponseCode ="+conn.getResponseCode());
   }

Cet appel renverra le code de réponse = 200 signifie que la connexion est réussie.

Pour plus de détails et un exemple d'exemple, vous pouvez vous référer à URL .

Shirishkumar Bari
la source
1
Google Play Store rejettera cela. Ils verront que vous ignorez X509Certificate lors de l'analyse de l'APK.
Oliver Dixon
0

SSLHandshakeException peut être résolu de 2 manières.

  1. Incorporer SSL

    • Obtenez le SSL (en demandant à l'administrateur du système source, peut également être téléchargé par la commande openssl, ou tout navigateur télécharge les certificats)

    • Ajoutez le certificat dans le truststore (cacerts) situé dans JRE / lib / security

    • indiquez l'emplacement du truststore dans les arguments vm sous la forme "-Djavax.net.ssl.trustStore ="

  2. Ignorer SSL

    Pour ce n ° 2, veuillez visiter mon autre réponse sur un autre site Web stackoverflow: Comment intégrer la vérification SSL Ignorer les erreurs de certificat SSL avec Java

Amit Kaneria
la source
-1

Je pense que vous essayez de vous connecter à quelque chose à l'aide de SSL, mais que quelque chose fournit un certificat qui n'est pas vérifié par les autorités de certification racine telles que verisign. Par défaut, les connexions sécurisées ne peuvent être établies que si la personne qui tente de se connecter sait les clés de contrepartie ou un autre verndor tel que verisign peuvent intervenir et dire que la clé publique fournie est en effet correcte.

ALL OS fait confiance à une poignée d'autorités de certification et de petits émetteurs de certificats doivent être certifiés par l'un des grands certificateurs faisant une chaîne de certificateurs si vous comprenez ce que je veux dire ...

Quoi qu'il en soit, pour revenir au point ... J'ai eu un problème similaire lors de la programmation d'une applet java et d'un serveur java (j'espère qu'un jour j'écrirai un article de blog complet sur la façon dont j'ai fait fonctionner toute la sécurité :))

En substance, ce que je devais faire était d'extraire les clés publiques du serveur et de les stocker dans un magasin de clés à l'intérieur de mon applet et lorsque je me suis connecté au serveur, j'ai utilisé ce magasin de clés pour créer une fabrique de confiance et cette fabrique de confiance pour créer le ssl lien. Il existe également des procédures alternatives telles que l'ajout de la clé à l'hôte de confiance de la JVM et la modification du magasin de confiance par défaut au démarrage.

Je l'ai fait il y a environ deux mois et je n'ai pas de code source sur moi pour le moment .. utilisez Google et vous devriez être en mesure de résoudre ce problème. Si vous ne pouvez pas m'envoyer un message et que je peux vous fournir le code source pertinent pour le projet .. Je ne sais pas si cela résout votre problème puisque vous n'avez pas fourni le code qui cause ces exceptions. De plus, je travaillais avec des applets et je ne voyais pas pourquoi cela ne fonctionnait pas sur les Serverlets ...

PS Je ne peux pas obtenir le code source avant le week-end car SSH externe est désactivé dans mon bureau :(

Oussama Javed
la source
1
PS J'ai trouvé ce code java en ligne pour extraire et stocker les clés publiques de mon serveur alors continuez à chercher sur Google ou attendez le dimanche
Osama Javed
-8

Maintenant, j'ai résolu ce problème de cette façon,

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.OutputStream;
// Create a trust manager that does not validate certificate chains like the 
default TrustManager[] trustAllCerts = new TrustManager[] {
    new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
        public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
            //No need to implement. 
        }
        public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
            //No need to implement. 
        }
    }
};
// 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 (Exception e) {
    System.out.println(e);
}
Evelyn Condes
la source
4
«Pas besoin de mettre en œuvre» est complètement et totalement incorrect. Vous venez de rendre votre connexion SSL non sécurisée. Ne fais pas ça.
Marquis of Lorne