Принять самоподписанный сертификат 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.

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

Опция 1

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

 \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 или, что еще лучше, сервер использует «настоящий» сертификат, подписанный известным ЦС.

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

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

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

2: Сохраните строку в файле с именем «DST Root CA X3.pem». Обязательно добавьте строки «—– BEGIN CERTIFICATE —–» и «—– END CERTIFICATE —–» в файле в начале и в конце.

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 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 будет скопирован в путь к classам и загружен оттуда. На данный момент я не тестировал другие сайты ssl, но если вышеуказанный код «цепочки» в этом сертификате, то они тоже будут работать, но опять же, я не знаю.

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

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

 SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial(new TrustSelfSignedStrategy()) .build(); SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext); Registry reg = RegistryBuilder.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 (например, в производстве), даже если они не работают на производственном оборудовании.

Вместо того, чтобы устанавливать фабрику сокетов по умолчанию (какой ИМО плохой) – 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 или в вашем classе приложений.

 NukeSSLCerts.nuke(); 

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

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

EDIT В пользу семнадцати (!) Downvoters и многочисленных комментаторов ниже, которые, очевидно, на самом деле не читали то, что я здесь написал, это не джериамида против самоподписанных сертификатов. Нет ничего плохого в самоподписанных сертификатах при правильной реализации. Но правильный способ их реализации состоит в том, чтобы обеспечить безопасный доступ к сертификату через автономный процесс, а не через неавторизованный канал, который они будут использовать для аутентификации. Неужели это очевидно? Это, безусловно, очевидно для каждой организации, в которой я когда-либо работал с точки зрения безопасности, от банков с тысячами филиалов до моих собственных компаний. Клиентское «базовое« решение »доверять всем сертификатам, включая самозаверяющие сертификаты, подписанные абсолютно кем угодно, или любое юридическое лицо, устанавливающее себя как ЦС, ipso facto не защищено. Он просто играет в безопасности. Это бессмысленно. У вас есть конфиденциальный, защищенный от несанкционированного доступа, ответный ответ с впрыском, с … кем-то. Кто-нибудь. Человек посередине. Инициатор. Кто-нибудь. Вы можете просто использовать открытый текст.

  • Использовать самоподписанный сертификат cURL?
  • Импорт PEM в хранилище ключей Java
  • Java SSL: как отключить проверку имени хоста
  • Java SSLHandshakeException «нет общих наборов шифров»
  • Как узнать, был ли запрос на сервлет выполнен с использованием HTTP или HTTPS?
  • HTTP-HTTPS-туннель
  • Повторное использование сеансов SSL в Android с HttpClient
  • как получить закрытый ключ из файла PEM?
  • веб-просмотр android с сертификатом клиента
  • Как отключить резерв SSL и использовать только TLS для исходящих подключений в .NET? (Смягчение пуделя)
  • Преобразовать .pem в .crt и .key
  • Давайте будем гением компьютера.