Примите самозаверяющий сертификат ssl сервера в клиенте Java



это выглядит как стандартный вопрос, но я не мог найти четкие направления в любом месте.



У меня есть код java, пытающийся подключиться к серверу с, вероятно, самозаверяющим (или истекшим) сертификатом. Код сообщает о следующей ошибке:



[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


Как я понимаю, я должен использовать keytool и скажите java, что это нормально, чтобы разрешить это соединение.



все инструкции по устранению этой проблемы предполагают, что я полностью владею keytool, например




сгенерировать закрытый ключ для сервера и импортировать его в хранилище ключей




есть ли кто-нибудь, кто может опубликовать подробные инструкции?



Я запускаю unix, поэтому сценарий bash будет лучше всего.



Не уверен, что это важно, но код выполняется в jboss.

1012   6  

6 ответов:

у вас есть в основном два варианта здесь: добавить самозаверяющий сертификат в свой JVM truststore или настроить свой клиент на

1

экспортируйте сертификат из Вашего браузера и импортируйте его в свой JVM truststore (чтобы установить цепочку доверия):

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

Отключить Проверку Сертификатов:

// 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) {
} 

отметим, что Я вообще не рекомендую вариант № 2. Отключение доверительного управляющего поражения некоторых частей SSL и делает вас уязвимым для атак злоумышленников. Предпочтите Вариант №1 или, еще лучше, чтобы сервер использовал "реальный" сертификат, подписанный известным CA.

я преследовал эту проблему до поставщика сертификатов, который не является частью доверенных хостов JVM по умолчанию с JDK 8u74. Поставщик является www.identrust.com, но это был не тот домен, к которому я пытался подключиться. Этот домен получил свой сертификат от этого поставщика. Смотрите будет ли кросс-корень покрывать доверие по списку по умолчанию в JDK/JRE? -- прочитайте несколько записей. Также смотрите какие браузеры и операционные системы поддерживают Давай Шифровать.

Итак, чтобы подключиться к интересующему меня домену, у которого был сертификат, выданный от identrust.com Я сделал следующие шаги. В принципе, я должен был получить identrust.com (DST Root CA X3) сертификат, которому будет доверять JVM. Я смог сделать это с помощью Apache HttpComponents 4.5 вот так:

1: Получить сертификат от indettrust в Инструкции По Загрузке Цепочки Сертификатов. Нажмите на кнопку DST Root CA X3 ссылка на сайт.

2: сохраните строку в файл с именем " DST Root CA X3.УГР." Будьте уверены, чтобы добавить строки "-----начните сертификата-----" и "-----конечный сертификат-----" в файле в начале и в конце.

3: создайте файл хранилища ключей java, cacerts.JKS-файл с помощью следующей команды:

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

4: скопируйте полученные cacerts.JKS keystore в каталог ресурсов вашего приложения java / (maven).

5: используйте следующий код для загрузки этого файла и прикрепите его к Apache 4.5 HttpClient. Это решит проблему для всех доменов, которые имеют сертификаты, выданные indetrust.com util oracle включает сертификат в хранилище ключей по умолчанию 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();

когда проект строит, то cacerts.jks будет скопирован в путь к классам и загружен оттуда. На данный момент я не тестировал другие сайты ssl, но если приведенный выше код "цепочки" в этом сертификате, то они тоже будут работать, но опять же, я этого не делаю знать.

ссылки: пользовательский контекст SSL и как я могу принять самозаверяющий сертификат с Java HttpsURLConnection?

Apache HttpClient 4.5 поддерживает прием самозаверяющих сертификатов:

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

это создает фабрику сокетов SSL, которая будет использовать TrustSelfSignedStrategy, регистрирует пользовательский диспетчер подключений выполняет HTTP-запрос GET через диспетчер подключений.

Я согласен с теми, кто скандирует "не делайте этого в производстве", однако есть варианты использования для принятия самозаверяющих сертификатов вне производства; мы используем их в автоматических интеграционных тестах, так что мы используем SSL (как в производстве), даже если он не работает на производственном оборудовании.

вместо установки фабрики сокетов по умолчанию (что IMO-это плохо) - yhis просто повлияет на текущее соединение, а не на каждое соединение SSL, которое вы пытаетесь открыть:

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

доверять всем сертификатам SSL:- Вы можете обойти SSL, если хотите протестировать на тестовом сервере. Но не используйте этот код для производства.

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

}

пожалуйста, вызовите эту функцию в функции onCreate () в Activity или в вашем классе приложений.

NukeSSLCerts.nuke();

Это может быть использовано для залпа в Android.

Если "они" используют самозаверяющий сертификат, они должны предпринять шаги, необходимые для использования их сервера. В частности, это означает предоставление их сертификата вам в автономном режиме надежным способом. Так заставь их сделать это. Затем вы импортируете это в свой truststore с помощью keytool, как описано в справочном руководстве JSSE. Даже не думайте о небезопасном TrustManager, размещенном здесь.

EDIT в интересах семнадцать (!) downvoters и многочисленные комментаторы ниже, которые явно не читали то, что я написал здесь, это не иеремиада против самозаверяющих сертификатов. Нет ничего плохого в самозаверяющих сертификатах при правильной реализации.а, правильный способ их реализации заключается в том, чтобы сертификат был доставлен безопасно через автономный процесс,, а не через непроверенные канал они будут используется для аутентификации. Разве это не очевидно? Это, безусловно, очевидно для каждой организации, знающей о безопасности, в которой я когда-либо работал, от банков с тысячами филиалов до моих собственных компаний. Клиентская кодовая база "решение" доверия все сертификаты, в том числе самозаверяющие сертификаты, подписанные абсолютно кем угодно или любым арбитражным органом, создающим себя в качестве CA, это ipso facto не безопасно. Это просто игра в безопасность. Это бессмысленно. Вы имеете Приватный, tamperproof, ответ-доказательство, впрыск-доказательство разговор С... кто-то. Кто-нибудь. Человек в середине. Самозванец. Кто-нибудь. Вы можете также просто использовать обычный текст.

Comments

    Ничего не найдено.