Javax.net.ssl.SSLHandshakeException Hatası nasıl çözülür?


101

Ürün listesini almak için envanter API'sini kurmak için VPN ile bağlantı kurdum ve sorunsuz çalışıyor. Web hizmetinden sonucu aldığımda ve UI'ye bağlandığımda. Ayrıca PayPal'ı, ödeme için arama yaptığımda Ekspres ödeme yapma uygulamasına entegre ettim, bu hatayla karşılaşıyorum. Arka uç işlemi için servlet kullanıyorum. Bu sorunun nasıl çözüleceğini söyleyen var mı?

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

1
Bilmek istediğim şey, bu durumda tam olarak hangi hedef vardı ... Bir istisna elde edersiniz, ancak hedef hakkında hiçbir bilgi almazsınız, bu beklediğinizden farklı olabilir .. Böyle bir durum var, eminim bağlantım sertifikası var ve hala bu istisnayı alıyorum
ante.sabo

Yanıtlar:


151

Öncelikle, bağlanmaya çalıştığınız sunucudan genel sertifikayı almanız gerekir. Bu, sunucu yöneticisiyle iletişim kurmak ve sormak, indirmek için OpenSSL kullanmak veya bu bir HTTP sunucusu gibi göründüğü için herhangi bir tarayıcıyla ona bağlanmak, sayfanın güvenlik bilgilerini görüntülemek gibi çeşitli şekillerde yapılabilir. ve sertifikanın bir kopyasını kaydetme. (Google, belirli tarayıcınız için tam olarak ne yapmanız gerektiğini size söyleyebilmelidir.)

Artık sertifikanız bir dosyaya kaydedildiğine göre, JVM'nizin güven deposuna eklemeniz gerekir. At $JAVA_HOME/jre/lib/security/JRE için veya $JAVA_HOME/lib/securityJDKs için, adlı bir dosya var cacertsJava ile gelir ve tanınmış Sertifika Yetkilileri kamu sertifikalarını içeren. Yeni sertifikayı içe aktarmak için, cacerts'a yazma iznine sahip bir kullanıcı olarak keytool'u çalıştırın:

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

Büyük ihtimalle sizden bir şifre isteyecektir. Java ile birlikte gönderilen varsayılan şifre changeit. Neredeyse kimse onu değiştirmez. Bu nispeten basit adımları tamamladıktan sonra, güvenli bir şekilde ve doğru sunucuyla ve yalnızca doğru sunucuyla (özel anahtarlarını kaybetmedikleri sürece) konuştuğunuzun garantisiyle iletişim kuracaksınız.


12
"Çalışmama" dan biraz daha fazla ayrıntıya ihtiyacım olacak. Sorunuzu denedikleriniz ve bazı hata çıktılarıyla güncellemeyi deneyin. Ne yazık ki, uyku vaktimi çok geçti, bu yüzden belki başka biri sorularınızı cevaplayabilir. Bu da çok yaygın bir durumdur. Anahtar araç dokümanları da dahil olmak üzere bu konuda pek çok bilgiyi çevrimiçi olarak bulabilirsiniz .
Ryan Stewart

Temel olarak PayPal sertifikası eklemem gerekiyor. Adımlarınızı yaptım ve uygun yere sertifika da ekledim. sonra uygulamayı çalıştırıyorum, aynı hatayı mı söylüyor?
selladurai

Aslında sorun değil tarayıcı ve envanter listesi almak için VPN'e bağlandım o sırada PayPal ile ödeme yapıyorum, SSL hatası diyor ama çevrimdışı verileri veya sıcak kodlanmış verileri kullanıyorum, çalıştığı anlamına geliyor.
selladurai

4
@selladurai: Paypal için bir sertifika almanıza gerek yok. Cacerts dosyanız bozulmadıkça veya değiştirilmedikçe, tüm güvenilir kök sertifikaları içermeli ve paypal'ın sertifikası bunlardan birine kadar izlenebilmelidir. İyi olduğunu bildiğiniz bir cacerts kopyasını alıp yerine onu denemeyi deneyebilirsiniz. Sorun devam ederse, aslında paypal'a bağlanmıyor olabilirsiniz.
Ryan Stewart

@RyanStewart onu bir şekilde cam balığına aktarmam gerekiyor mu? Çünkü .cer dosyasını java ana dizinimdeki cacert'ime ekledim, ancak cam balığı onu kullanmıyor gibi görünüyor, bu yüzden hala hatayı alıyorum.
Ced

15

Şimdi bu sorunu bu şekilde çözdüm,

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);
}

Elbette bu çözüm, keytoolörneğin geçici sertifikalarla yerel testler kullanılarak gerekli sertifikaların kurulmasının mümkün olmadığı senaryolarda kullanılmalıdır .


53
Vay canına, buna "düzeltme" demekten çekinirim. Temelde güvenliği kapattınız. Evet, veriler yine de şifrelenecek, ancak konuşmayı beklediğiniz kişiyle konuştuğunuzun garantisine sahip değilsiniz. Doğru çözüm, hedef sunucunuzun ortak anahtarını elde etmek ve bunu bağlantıyı sağlayan JVM'nin güven deposuna aktarmaktır.
Ryan Stewart

1
uygun bir çözüm için cevabımı görün
Ryan Stewart

Ne örneği? Cevabım ihtiyacınız olan tüm adımları içermelidir.
Ryan Stewart


3
Burada gösterilen kod, bir geliştirici sunucusuna karşı çok basit bir test yazıyorsanız faydalı görünüyor, yine de Üretim için buna güvenmem.
Jason D

12

URL'ye ne zaman bağlanmaya çalışsak,

diğer sitedeki sunucu https protokolünde çalışıyorsa ve sertifikada sağlanan bilgiler aracılığıyla iletişim kurmamızı zorunlu kılıyorsa, şu seçeneğe sahibiz:

1) sertifikayı isteyin (sertifikayı indirin), bu sertifikayı trustore'da içe aktarın. Varsayılan trustore java kullanımları \ Java \ jdk1.6.0_29 \ jre \ lib \ security \ cacerts konumunda bulunabilir, bu durumda URL bağlantısına yeniden bağlanmayı denersek kabul edilecektir.

2) Normal iş durumlarında, kuruluşlarda dahili URL'lere bağlanıyor olabiliriz ve bunların doğru olduğunu biliyoruz. Bu gibi durumlarda, bunun doğru URL olduğuna güvenirsiniz. Yukarıdaki gibi durumlarda, belirli bir URL'ye bağlanmak için sertifikayı saklamayı zorunlu kılmayan kod kullanılabilir.

2 numaralı nokta için aşağıdaki adımları izlemeliyiz:

1) HttpsURLConnection için HostnameVerifier'i ayarlayan ve tüm durumlar için true döndüren, yani trustStore'a güvendiğimiz anlamına gelen yöntemi aşağıya yazın.

  // 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) URL'ye bağlanmayı denemeden önce doTrustToCertificates'i çağıran yöntemi aşağıya yazın

    // 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());
   }

Bu çağrı yanıt kodunu döndürecektir = 200 bağlantının başarılı olduğu anlamına gelir.

Daha fazla ayrıntı ve örnek örnek için URL'ye başvurabilirsiniz .


1
Google Play mağazası bunu reddedecek. APK taraması sırasında X509Certificate'ı göz ardı ettiğinizi göreceklerdir.
Oliver Dixon

0

SSLHandshakeException 2 yolla çözülebilir.

  1. SSL içeren

    • SSL'yi edinin (kaynak sistem yöneticisine sorarak, openssl komutuyla da indirilebilir veya herhangi bir tarayıcı, sertifikaları indirir)

    • Sertifikayı JRE / lib / security adresinde bulunan truststore'a (cacerts) ekleyin

    • vm bağımsız değişkenlerinde güven deposu konumunu "-Djavax.net.ssl.trustStore =" olarak sağlayın

  2. SSL'yi Yoksaymak

    Bu # 2 için, lütfen başka bir stackoverflow web sitesindeki diğer cevabımı ziyaret edin: SSL doğrulaması nasıl yapılır Java ile SSL Sertifika Hatalarını Yoksay


-1

SSL kullanarak bir şeye bağlanmaya çalıştığınıza inanıyorum, ancak bir şeyin verisign gibi kök sertifika yetkilileri tarafından doğrulanmayan bir sertifika sağladığına inanıyorum. Temelde, varsayılan olarak güvenli bağlantılar ancak bağlanmaya çalışan kişi biliyorsa kurulabilir karşı tarafın anahtarları veya verisign gibi başka bir verndor devreye girebilir ve sağlanan genel anahtarın gerçekten doğru olduğunu söyleyebilir ..

TÜM OS'ler, bir avuç sertifika yetkilisine güveniyor ve daha küçük sertifika veren kuruluşlar, bir sertifika zinciri oluşturan büyük onaylayıcılardan biri tarafından onaylanmalıdır.

Her neyse, konuya geri dönersek .. Bir java uygulaması ve bir java sunucusu programlarken benzer bir sorun yaşadım (Umarım bir gün, çalışmak için tüm güvenliği nasıl sağladığım hakkında eksiksiz bir blog yazısı yazacağım :))

Temelde yapmam gereken, genel anahtarları sunucudan çıkarmak ve uygulamamın içindeki bir anahtar deposunda saklamaktı ve sunucuya bağlandığımda bu anahtar deposunu bir güven fabrikası oluşturmak için kullandım ve bu anahtar deposunu ssl'yi oluşturmak için kullandım. bağ. Anahtarın JVM'nin güvenilir ana bilgisayarına eklenmesi ve başlangıçta varsayılan güven deposunun değiştirilmesi gibi alternatif prosedürler de vardır.

Bunu yaklaşık iki ay önce yaptım ve şu anda üzerimde kaynak kodu yok .. google'ı kullanın ve bu sorunu çözebilmelisiniz. Bana geri mesaj gönderemezseniz ve size proje için ilgili kaynak kodunu sağlayabilirim .. Bu istisnalara neden olan kodu sağlamadığınız için bunun sorununuzu çözüp çözmediğini bilmeyin. Dahası, neden Serverletlerde çalışmayacağını anlayamadığımı düşündüğüm uygulamalarla çalışıyordum ...

Not: Ofisimde harici SSH devre dışı bırakıldığı için hafta sonundan önce kaynak kodunu alamıyorum :(


1
Not: Bu java kodunu sunucumun genel anahtarlarını çıkarmak ve depolamak için çevrimiçi buldum, bu yüzden googling yapmaya devam edin veya pazar gününe kadar bekleyin
Usame Javed

-8

Şimdi bu sorunu bu şekilde çözdüm,

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);
}

4
"Uygulamaya gerek yok" tamamen ve tamamen yanlıştır. SSL bağlantınızı az önce güvensiz hale getirdiniz. Bunu yapma.
Marquis of Lorne
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.