Як вирішити помилку javax.net.ssl.SSLHandshakeException?


101

Я підключився до VPN, щоб налаштувати API інвентаризації, щоб отримати список продуктів, і він працює добре. Як тільки я отримую результат від веб-сервісу, і я прив’язуюсь до інтерфейсу користувача. А також я інтегрував PayPal у свою заявку на оформлення експрес-замовлення, коли я здійснюю дзвінок про оплату, я стикаюся з цією помилкою. Я використовую сервлет для бек-енд-процесу. Хтось може сказати, як виправити це питання?

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
що я хотів би знати, яка саме ціль була в тому випадку ... Ви отримуєте виняток, але ви не отримуєте жодної інформації про ціль, яка може відрізнятись від того, що ви очікуєте .. У мене є такий випадок, я впевнений, що моє посилання має сертифікат, і я все ще отримую цей виняток
ante.sabo

Відповіді:


151

Спочатку потрібно отримати публічний сертифікат від сервера, до якого ви намагаєтесь підключитися. Це можна зробити різними способами, наприклад, зв’язатися з адміністратором сервера та попросити його, використовуючи OpenSSL для його завантаження. , або, оскільки це, здається, HTTP-сервер, підключення до нього з будь-яким браузером, перегляд інформації про безпеку сторінки. та збереження копії сертифіката. (Google повинен мати можливість сказати вам, що саме робити для вашого конкретного веб-переглядача.)

Тепер, коли у вас збережений сертифікат у файлі, вам потрібно додати його до довіреного магазину JVM. У $JAVA_HOME/jre/lib/security/JRE або $JAVA_HOME/lib/securityдля JDK є файл з назвою cacerts, який поставляється разом з Java і містить публічні сертифікати відомих органів, що сертифікують. Щоб імпортувати новий cert, запустіть keytool як користувач, який має дозвіл писати в cacerts:

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

Він, швидше за все, запитає вас про пароль. Пароль за замовчуванням, що постачається з Java, - це changeit. Майже ніхто її не змінює. Виконавши ці порівняно прості дії, ви будете спілкуватися надійно та із впевненістю, що ви спілкуєтесь із правильним сервером та лише правильним сервером (доки вони не втратять приватний ключ).


12
Мені потрібно трохи детальніше, ніж "не працює". Спробуйте оновити своє запитання тим, що ви намагалися, і помилками. На жаль, він пройшов повз мого сну, тому, можливо, хтось інший зможе відповісти на ваші запитання. Це теж дуже поширена ситуація. Ви можете знайти багато інформації про нього в Інтернеті, включаючи документи з ключових інструментів .
Райан Стюарт

В основному мені потрібно включити PayPal cert. Я зробив ваші кроки, і cert також додав у відповідному місці. то я запускаю додаток, воно говорить ту саму помилку?
selladurai

Насправді він працює добре, немає проблем із браузером, і я підключив VPN, щоб отримати список інвентаря в той час, я здійснюю оплату за допомогою PayPal, мовляв, помилка SSL, але я використовую офлайн-дані або гаряче кодовані дані, це означає, що це працює.
selladurai

4
@selladurai: Вам не потрібно імпортувати сертифікат для paypal. Якщо ваш файл кесерів не був пошкоджений або модифікований, він повинен містити всі довірені кореневі сертифікати, і kert paypal повинен мати можливість відстежуватися до одного з них. Ви можете спробувати отримати копію касертів, які ви знаєте, що це добре, і спробувати це. Якщо проблема не зникає, можливо, ви фактично не підключаєтесь до paypal.
Райан Стюарт

@RyanStewart мені потрібно якось імпортувати його до рибки? Оскільки я додав файл .cer до мого кестеру в домашній каталог Java, але, схоже, скляна рибка не використовує його, тому я все ще отримую помилку.
Ced

15

Тепер я вирішив це питання таким чином,

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

Звичайно, це рішення слід застосовувати лише у сценаріях, де неможливо встановити необхідні сертифікати, використовуючи, keytoolнаприклад, локальне тестування з тимчасовими сертифікатами.


52
Нічого собі, я б вагався, називаючи це "виправленням". Ви в основному просто вимкнули безпеку. Так, дані все ще будуть зашифровані, але у вас немає гарантії, що ви спілкуєтесь з тим, з ким очікуєте спілкуватися. Правильне рішення - отримати відкритий ключ вашого цільового сервера та імпортувати його до довіреного сховища JVM, який здійснює з'єднання.
Райан Стюарт

1
дивіться мою відповідь на відповідне рішення
Райан Стюарт

Приклад чого? У моїй відповіді повинні бути всі необхідні кроки.
Райан Стюарт


3
Код, показаний тут, виглядає корисним, якщо ви пишете дуже простий тест на сервер розробників, я б не покладався на нього для виробництва.
Джейсон Д

12

Кожного разу, коли ми намагаємося підключитися до URL-адреси,

якщо сервер на іншому сайті працює за протоколом https і вимагає спілкуватися через інформацію, надану в сертифікаті, то у нас є наступний варіант:

1) запитати сертифікат (завантажити сертифікат), імпортувати цей сертифікат у trustore. Використання Java Trustore за замовчуванням можна знайти в \ Java \ jdk1.6.0_29 \ jre \ lib \ security \ cacerts, тоді, якщо ми спробуємо підключитися до URL-з'єднання, буде прийнято.

2) У звичайних бізнес-випадках ми можемо підключатися до внутрішніх URL-адрес в організаціях, і ми знаємо, що вони правильні. У таких випадках ви довіряєте, що це правильна URL-адреса. У таких випадках вище може використовуватися код, який не вимагає зберігати сертифікат для підключення до певної URL-адреси.

для точки № 2 ми повинні виконати наступні кроки:

1) напишіть нижче метод, який встановлює HostnameVerifier для HttpsURLConnection, який повертає істину для всіх випадків, тобто ми довіряємо 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) напишіть нижче метод, який викликає doTrustToCertificate перед тим, як спробувати підключитися до 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());
   }

Цей виклик поверне код відповіді = 200 означає, що з'єднання успішне.

Більш детально та приклад прикладу можна посилатись на URL .


1
Google Play магазин відкине це. Вони побачать, що ви ігноруєте X509Certificate під час сканування APK.
Олівер Діксон

0

Я вважаю, що ви намагаєтесь підключитися до чогось за допомогою SSL, але щось надає сертифікат, який не перевіряється кореневими органами сертифікації, такими як verisign. ключі контрагентів або якийсь інший постачальник, наприклад verisign, можуть зайти і сказати, що відкритий ключ дійсно правильний ..

ВСІ довіри ОС декілька сертифікаційних органів та менших емітентів сертифікатів повинні бути сертифіковані одним із великих сертифікаторів, які складають ланцюжок сертифікаторів, якщо ви отримаєте те, що я маю на увазі ...

У будь-якому випадку повертаюсь до суті .. У мене виникли подібні проблеми при програмуванні аплету Java та сервера java (сподіваюся, якихось день я напишу повний блог-повідомлення про те, як я отримав всю безпеку для роботи :))

По суті, мені довелося витягнути відкриті ключі з сервера і зберегти його в сховищі ключів всередині мого аплету, і коли я підключився до сервера, я використовував цей магазин ключів для створення фабрики довіри і цієї фабрики довіри для створення ssl з'єднання. Існують також процедури alterante, такі як додавання ключа до надійного хоста JVM та зміна довіреного сховища за замовчуванням при запуску ..

Я зробив це близько двох місяців тому і не маю вихідного коду на мені прямо зараз. Використовуйте google, і ви повинні мати можливість вирішити цю проблему. Якщо ви не можете надіслати мені повідомлення, і я можу надати вам належний вихідний код для проекту. Не знаю, чи вирішує це ваша проблема, оскільки ви не надали код, який викликає ці винятки. Крім того, я працював над апплетами, думав, що не можу зрозуміти, чому він не працює на сервертах ...

PS Я не можу отримати вихідний код до вихідних, оскільки зовнішній SSH в моєму кабінеті відключений :(


1
PS Я знайшов цей код Java в Інтернеті, щоб витягувати та зберігати відкриті ключі мого сервера, тому продовжуйте гугнути або чекати до неділя
Осама Джавед

0

SSLHandshakeException можна вирішити двома способами.

  1. Включення SSL

    • Отримайте SSL (запитавши у вихідного системного адміністратора, його також можна завантажити командою openssl або будь-які браузери завантажують сертифікати)

    • Додайте сертифікат у довірений магазин (cacerts), розташований за адресою JRE / lib / security

    • вкажіть розташування довіри для аргументів vm як "-Djavax.net.ssl.trustStore ="

  2. Ігнорування SSL

    Для цього # 2, будь ласка, відвідайте іншу відповідь на іншому веб-сайті stackoverflow : Як ввімкнути перевірку SSL Ігнорувати помилки сертифіката SSL з Java


-8

Тепер я вирішив це питання таким чином,

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
"Не потрібно реалізовувати" абсолютно і зовсім неправильно. Ви тільки що зробили ваше SSL-з'єднання незахищеним. Не робіть цього.
Маркіз Лорн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.