Как обработать недопустимые сертификаты SSL с Apache HttpClient? [дубликат]

Этот вопрос уже имеет ответ здесь:

Я знаю, существует много различных вопросов и столько ответов об этой проблеме... Но я не могу понять...

Я имею: ubuntu-9.10-desktop-amd64 + NetBeans6.7.1, установленный, "как" от прочь. представитель мне нужно соединение с некоторым сайтом по HTTPS. Для этого я использую HttpClient Apache.

Из учебного руководства я читал:

"После того как Вы имеете JSSE, правильно установленный, защищаете Связь HTTP по SSL, должен быть как
простой как простая Связь HTTP". И некоторый пример:

HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.verisign.com/"); 
try { 
  httpclient.executeMethod(httpget);
  System.out.println(httpget.getStatusLine());
} finally {
  httpget.releaseConnection();
}

К настоящему времени я пишу это:

HttpClient client = new HttpClient();

HttpMethod get = new GetMethod("https://mms.nw.ru");
//get.setDoAuthentication(true);

try {
    int status = client.executeMethod(get);
    System.out.println(status);

    BufferedInputStream is = new BufferedInputStream(get.getResponseBodyAsStream());
    int r=0;byte[] buf = new byte[10];
    while((r = is.read(buf)) > 0) {
        System.out.write(buf,0,r);
    }

} catch(Exception ex) {
    ex.printStackTrace();
}

В результате у меня есть ряд ошибок:

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
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1627)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:204)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:198)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:994)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:142)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:533)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:471)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:904)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1132)
        at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:643)
        at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:78)
        at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
        at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(HttpConnection.java:828)
        at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2116)
        at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
        at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
        at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
        at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
        at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
        at simpleapachehttp.Main.main(Main.java:41)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:302)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:205)
        at sun.security.validator.Validator.validate(Validator.java:235)
        at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:147)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:230)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:270)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:973)
        ... 17 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:191)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:297)
        ... 23 more

Что имеет меня, чтобы сделать для создания самого простого соединения SSL? (Вероятно, без KeyManager и Доверительного менеджера и т.д., в то время как.)

120
задан Jakub Šturc 7 November 2019 в 09:05
поделиться

4 ответа

https://mms.nw.ru использует самозаверяющий сертификат, который, очевидно, не содержится в наборе доверенных менеджеров по умолчанию.

Вам потребуется одно из следующих:

  • Настройте SSLContext с помощью TrustManager, который принимает любой сертификат (см. ниже)

  • Настройте SSLContext с соответствующим хранилищем доверенных сертификатов, которое включает ваш сертификат

  • Добавьте сертификат для этого сайта в стандартную java доверенное хранилище.

Вот пример программы, которая создает (в основном бесполезный) контекст SSL, который принимает любой сертификат:

import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class SSLTest {

    public static void main(String [] args) throws Exception {
        // configure the SSLContext with a TrustManager
        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
        SSLContext.setDefault(ctx);

        URL url = new URL("https://mms.nw.ru");
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
        conn.setHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }
        });
        System.out.println(conn.getResponseCode());
        conn.disconnect();
    }

    private static class DefaultTrustManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }
}
154
ответ дан 24 November 2019 в 01:37
поделиться

Если у вас есть хранилище сертификатов Java (используя отличный класс InstallCert, созданный выше), вы можете заставить Java использовать его, передав "javax.net.ssl .trustStore "параметр при запуске java.

Пример:

java -Djavax.net.ssl.trustStore=/path/to/jssecacerts MyClassName
4
ответ дан 24 November 2019 в 01:37
поделиться

Из http://hc.apache.org/httpclient-3 .x / sslguide.html :

Protocol.registerProtocol("https", 
new Protocol("https", new MySSLSocketFactory(), 443));
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.whatever.com/");
try {
  httpclient.executeMethod(httpget);
      System.out.println(httpget.getStatusLine());
} finally {
      httpget.releaseConnection();
}

Где пример MySSLSocketFactory можно найти здесь . Он ссылается на TrustManager , который вы можете изменить, чтобы доверять всему (хотя вы должны это учитывать!)

10
ответ дан 24 November 2019 в 01:37
поделиться

https://mms.nw.ru , скорее всего, использует сертификат, выданный не центром сертификации. Следовательно, вам необходимо добавить сертификат в надежное хранилище ключей Java, как описано в , невозможно найти действительный путь сертификации для запрошенной цели :

При работе с работающим клиентом с сервером с поддержкой SSL, работающим в https протокол, вы можете получить ошибку 'не удалось найти действующий сертификат путь к запрошенной цели ', если сертификат сервера не выдается центр сертификации, но сам подписано или выпущено частной CMS.

Не паникуйте. Все, что вам нужно сделать, это добавьте сертификат сервера в свой надежное хранилище ключей Java, если ваш клиент написан на Java. Вы, возможно интересно, как будто у тебя нет доступа машина, на которой находится сервер установлен. Есть простая программа могу помочь тебе. Загрузите Java программу и запустите

% java InstallCert _web_site_hostname_

Эта программа открыла соединение с указанный хост и запустил SSL рукопожатие. Он напечатал исключение трассировка стека произошедшей ошибки и показывает сертификаты, используемые сервер. Теперь он предлагает вам добавить сертификат в надежное хранилище ключей.

Если вы передумали, введите 'q'. Если вы действительно хотите добавить сертификат, введите "1" или другое номера для добавления других сертификатов, даже сертификат CA, но обычно вы не хочу этого делать. Как только у вас есть сделал свой выбор, программа будет показать полный сертификат и затем добавил его в хранилище ключей Java с именем jssecacerts в текущем каталог.

Чтобы использовать его в своей программе, либо настроить JSSE, чтобы использовать его как доверие сохранить или скопировать в свой Каталог $ JAVA_HOME / jre / lib / security. Если вы хотите, чтобы все приложения Java признать сертификат надежным и не только JSSE, вы также можете перезапишите файл cacerts в этом каталог.

После всего этого JSSE сможет завершите рукопожатие с хозяином, что вы можете проверить, запустив программу снова.

Чтобы получить более подробную информацию, вы можете проверить Блог Лиланда Больше нет "невозможно найти" действительный путь сертификации к запрошенному target '

46
ответ дан 24 November 2019 в 01:37
поделиться