Как подключиться через HTTPS с помощью Jsoup? - PullRequest
22 голосов
/ 12 октября 2011

Он работает нормально по HTTP, но когда я пытаюсь использовать источник HTTPS, он выдает следующее исключение:

10-12 13:22:11.169: WARN/System.err(332): javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
10-12 13:22:11.179: WARN/System.err(332):     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:477)
10-12 13:22:11.179: WARN/System.err(332):     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:328)
10-12 13:22:11.179: WARN/System.err(332):     at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.setupSecureSocket(HttpConnection.java:185)
10-12 13:22:11.179: WARN/System.err(332):     at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:433)
10-12 13:22:11.189: WARN/System.err(332):     at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.makeConnection(HttpsURLConnectionImpl.java:378)
10-12 13:22:11.189: WARN/System.err(332):     at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:205)
10-12 13:22:11.189: WARN/System.err(332):     at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:152)
10-12 13:22:11.189: WARN/System.err(332):     at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:377)
10-12 13:22:11.189: WARN/System.err(332):     at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:364)
10-12 13:22:11.189: WARN/System.err(332):     at org.jsoup.helper.HttpConnection.execute(HttpConnection.java:143)

Вот соответствующий код:

try {
    doc = Jsoup.connect("https url here").get();
} catch (IOException e) {
    Log.e("sys","coudnt get the html");
    e.printStackTrace();
}

Ответы [ 9 ]

53 голосов
/ 12 октября 2011

Если вы хотите сделать это правильно и / или вам нужно иметь дело только с одним сайтом, то вам, в основном, нужно получить сертификат SSL соответствующего веб-сайта и импортировать его в хранилище ключей Java. Это приведет к созданию файла JKS, который вы в свою очередь установите в качестве хранилища доверенных сертификатов SSL перед использованием Jsoup (или java.net.URLConnection).

Вы можете получить сертификат в магазине вашего веб-браузера. Давайте предположим, что вы используете Firefox.

  1. Перейдите на указанный сайт с помощью Firefox, который в вашем случае https://web2.uconn.edu/driver/old/timepoints.php?stopid=10
  2. Слева в адресной строке вы увидите "uconn.edu" синим цветом (это указывает на действительный сертификат SSL)
  3. Нажмите на него для получения подробной информации, а затем нажмите на кнопку Дополнительная информация .
  4. В появившемся диалоговом окне безопасности нажмите кнопку Просмотр сертификата .
  5. В появившейся панели сертификатов перейдите на вкладку Подробно .
  6. Щелкните самый глубокий элемент иерархии сертификатов, в данном случае это «web2.uconn.edu», и, наконец, нажмите кнопку Export .

Теперь у вас есть web2.uconn.edu.crt файл.

Затем откройте командную строку и импортируйте ее в хранилище ключей Java с помощью команды keytool (это часть JRE):

keytool -import -v -file /path/to/web2.uconn.edu.crt -keystore /path/to/web2.uconn.edu.jks -storepass drowssap

-file должен указывать на местоположение файла .crt, который вы только что загрузили. -keystore должен указывать на местоположение сгенерированного файла .jks (который вы, в свою очередь, хотите установить в качестве хранилища доверенных сертификатов SSL). -storepass требуется, вы можете просто ввести любой пароль, который вы хотите, если он не менее 6 символов.

Теперь у вас есть web2.uconn.edu.jks файл. Наконец, вы можете установить его как хранилище доверенных сертификатов SSL перед подключением следующим образом:

System.setProperty("javax.net.ssl.trustStore", "/path/to/web2.uconn.edu.jks");
Document document = Jsoup.connect("https://web2.uconn.edu/driver/old/timepoints.php?stopid=10").get();
// ...

В качестве совершенно другой альтернативы, особенно когда вам нужно иметь дело с несколькими сайтами (т. Е. Вы создаете сканер для всемирной паутины), вы также можете указать Jsoup (в основном, java.net.URLConnection) слепо доверять всем SSL-сертификатам. , См. Также раздел «Работа с ненадежными или неправильно настроенными HTTPS-сайтами» в самом конце этого ответа: Использование java.net.URLConnection для запуска и обработки HTTP-запросов

12 голосов
/ 16 января 2018

В моем случае все, что мне нужно было сделать, это добавить .validateTLSCertificates (false) в моем соединении

Document doc  = Jsoup.connect(httpsURLAsString)
            .timeout(60000).validateTLSCertificates(false).get();

Мне также пришлось увеличить тайм-аут чтения, но я думаю, что это не имеет значения

8 голосов
/ 30 июля 2014

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

  1. Есть запрос github для добавления такой функциональности. Так что, возможно, скоро проблема будет решена: https://github.com/jhy/jsoup/pull/343 редактирование: запрос Github был разрешен, и метод для отключения проверки сертификата: validateTLSCertificates (логическая проверка)
  2. На основании http://www.nakov.com/blog/2009/07/16/disable-certificate-validation-in-java-ssl-connections/ Я нашел решение, которое, кажется, работает (по крайней мере, в моем сценарии, где jsoup 1.7.3 вызывается как часть задачи maven). Я обернул его в метод disableSSLCertCheck(), который я вызываю до самого первого Jsoup.connect ().

Прежде чем использовать этот метод , вы должны быть действительно уверены, что понимаете, что делаете там - не проверять SSL-сертификаты - это действительно глупо. Всегда используйте правильные сертификаты SSL для ваших серверов, которые подписаны общепринятым CA. Если вы не можете позволить себе общепринятый центр сертификации, используйте правильные SSL-сертификаты, однако ответ @BalusC принят выше. Если вы не можете настроить правильные сертификаты SSL (что никогда не должно иметь место в производственных средах), может работать следующий метод:

    private void disableSSLCertCheck() throws NoSuchAlgorithmException, KeyManagementException {
    // Create a trust manager that does not validate certificate chains
    TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
            }
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
            }
        }
    };

    // Install the all-trusting trust manager
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

    // Create all-trusting host name verifier
    HostnameVerifier allHostsValid = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    // Install the all-trusting host verifier
    HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
    }
3 голосов
/ 09 мая 2013

У меня была та же проблема, но я пошел ленивым путем - скажите вашему приложению игнорировать сертификат и продолжить в любом случае.

Я получил код отсюда: Как использовать локальныйHTTPS URL в java?

Вам нужно будет импортировать эти классы, чтобы он работал:

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

Просто запустите этот метод где-нибудь, прежде чем пытаться установить соединение, и вуаляОн просто доверяет сертификату, несмотря ни на что.Конечно, это не поможет, если вы действительно хотите удостовериться, что сертификат является реальным, но подходит для мониторинга ваших внутренних веб-сайтов и т. Д.

1 голос
/ 05 апреля 2019

Так как это решение:

Document doc  = Jsoup.connect(httpsURLAsString)
            .timeout(60000).validateTLSCertificates(false).get();

Теперь показывает предупреждения об устаревании и в скором времени будет удален, вот альтернативный вариант (в основном та же идея, что предложена в ответ ), но для подавления предупреждений сертификата для конкретного соединения JSoup:

Котлин


val document = Jsoup.connect("url")
        .sslSocketFactory(socketFactory())
        .get()


private fun socketFactory(): SSLSocketFactory {
    val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
        @Throws(CertificateException::class)
        override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
        }

        @Throws(CertificateException::class)
        override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
        }

        override fun getAcceptedIssuers(): Array<X509Certificate> {
            return arrayOf()
        }
    })

    try {
        val sslContext = SSLContext.getInstance("TLS")
        sslContext.init(null, trustAllCerts, java.security.SecureRandom())
        return sslContext.socketFactory
    } catch (e: Exception) {
        when (e) {
            is RuntimeException, is KeyManagementException -> {
                throw RuntimeException("Failed to create a SSL socket factory", e)
            }
            else -> throw e
        }
    }
}

Java



 Document document = Jsoup.connect("url")
        .sslSocketFactory(socketFactory())
        .get();


  private SSLSocketFactory socketFactory() {
    TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
      public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return null;
      }

      public void checkClientTrusted(X509Certificate[] certs, String authType) {
      }

      public void checkServerTrusted(X509Certificate[] certs, String authType) {
      }
    }};

    try {
      SSLContext sslContext = SSLContext.getInstance("TLS");
      sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
      return sslContext.getSocketFactory();
    } catch (NoSuchAlgorithmException | KeyManagementException e) {
      throw new RuntimeException("Failed to create a SSL socket factory", e);
    }
  }

NB. Как уже упоминалось, игнорирование сертификатов не является хорошей идеей.

0 голосов
/ 04 августа 2018

У меня такая проблема была только в среде разработчиков.Решением этой проблемы было просто добавить несколько флагов, чтобы игнорировать SSL для ВМ:

-Ddeployment.security.TLSv1.1=false 
-Ddeployment.security.TLSv1.2=false
0 голосов
/ 22 февраля 2018

Я столкнулся с той же проблемой с Jsoup, я не смог подключиться и получить документ для URL https, но когда я изменил версию JDK с 1.7 на 1.8, проблема была решена.

Возможно,помочь вам :)

0 голосов
/ 11 декабря 2014

Попробуйте следующее (просто поставьте перед Jsoup.connect("https://example.com"):

    Authenticator.setDefault(new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(username, password.toCharArray());
        }
    });
0 голосов
/ 12 октября 2011

Я не эксперт в этой области, но я столкнулся с аналогичным исключением при попытке подключиться к веб-сайту через HTTPS с помощью API java.net.Браузер проделывает большую работу за вас в отношении SSL-сертификатов, когда вы посещаете сайт с использованием HTTPS.Однако, когда вы вручную подключаетесь к сайтам (используя HTTP-запросы вручную), всю эту работу по-прежнему необходимо выполнять.Сейчас я не знаю, что это за работа, но она связана с загрузкой сертификатов и размещением их там, где Java может их найти.Вот ссылка, которая, мы надеемся, укажет вам правильное направление.

http://confluence.atlassian.com/display/JIRA/Connecting+to+SSL+services

...