Примите самозаверяющий сертификат 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.
6 ответов:
у вас есть в основном два варианта здесь: добавить самозаверяющий сертификат в свой JVM truststore или настроить свой клиент на
1экспортируйте сертификат из Вашего браузера и импортируйте его в свой JVM truststore (чтобы установить цепочку доверия):
2<JAVA_HOME>\bin\keytool -import -v -trustcacerts -alias server-alias -file server.cer -keystore cacerts.jks -keypass changeit -storepass changeitОтключить Проверку Сертификатов:
// 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 yourpassword4: скопируйте полученные cacerts.JKS keystore в каталог ресурсов вашего приложения java / (maven).
5: используйте следующий код для загрузки этого файла и прикрепите его к Apache 4.5 HttpClient. Это решит проблему для всех доменов, которые имеют сертификаты, выданные
indetrust.comutil 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