Как подключиться через HTTPS с помощью Jsoup?
Он отлично работает через 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();
}
Ответы
Ответ 1
Если вы хотите сделать это правильно и/или вам нужно иметь дело только с одним сайтом, то вам нужно получить сертификат SSL соответствующего веб-сайта и импортировать его в хранилище ключей Java. Это приведет к созданию файла JKS, который вы в свою очередь установите в качестве хранилища доверенных сертификатов SSL перед использованием Jsoup (или java.net.URLConnection
).
Вы можете получить сертификат в своем интернет-магазине. Предположим, вы используете Firefox.
- Перейдите на соответствующий веб-сайт с помощью Firefox, который в вашем случае https://web2.uconn.edu/driver/old/timepoints.php?stopid=10.
- Слева в адресной строке вы увидите "uconn.edu" синим цветом (это указывает на действительный сертификат SSL)
- Нажмите на нее для получения подробной информации, а затем нажмите на кнопку "Дополнительная информация".
- В появившемся диалоговом окне безопасности нажмите кнопку "Просмотреть сертификат".
- В появившейся панели сертификатов перейдите на вкладку Details.
- Щелкните по самому глубокому элементу иерархии сертификатов, в данном случае это "web2.uconn.edu", и, наконец, нажмите кнопку "Экспорт".
Теперь у вас есть файл 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-запросов.
Ответ 2
В моем случае все, что мне нужно было сделать, это добавить в мое соединение .validateTLSCertificates(false)
Document doc = Jsoup.connect(httpsURLAsString)
.timeout(60000).validateTLSCertificates(false).get();
Мне также пришлось увеличить таймаут чтения, но я думаю, что это не имеет значения.
Ответ 3
Я наткнулся на ответы здесь и в связанном вопросе в моем поиске и хочу добавить две части информации, так как принятый ответ не соответствует моему совсем похожему сценарию, но есть дополнительное решение, которое подходит даже в этом case (cert и hostname не соответствуют тестовым системам).
Прежде чем использовать этот метод, вы должны быть уверены, что понимаете, что вы там делаете - не проверка сертификатов 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);
}
Ответ 4
У меня была такая же проблема, но она взяла ленивый маршрут - сообщите своему приложению, чтобы игнорировать сертификат и продолжать в любом случае.
Я получил код отсюда: Как использовать локальный URL HTTPS в 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;
Просто запустите этот метод где-нибудь, прежде чем пытаться установить соединение и вуаля, он просто доверяет сертификату независимо от того, что. Конечно, это не поможет, если вы действительно хотите убедиться, что сертификат реальный, но он хорош для мониторинга ваших собственных внутренних веб-сайтов и т.д.
Ответ 5
Я не эксперт в этой области, но я столкнулся с аналогичным исключением при попытке подключиться к сайту через HTTPS с помощью java.net API. Браузер много работает для вас в отношении сертификатов SSL при посещении сайта с помощью HTTPS. Однако, когда вы вручную подключаетесь к сайтам (используя HTTP-запросы вручную), все, что требуется, еще нужно сделать. Теперь я не знаю, что все это работает в точности, но оно связано с загрузкой сертификатов и помещением их туда, где Java может их найти. Здесь ссылка, которая, надеюсь, укажет вам в правильном направлении.
http://confluence.atlassian.com/display/JIRA/Connecting+to+SSL+services
Ответ 6
Я столкнулся с той же проблемой с Jsoup, я не смог подключиться и получить документ для URL https, но когда я изменил свою версию JDK с 1.7 на 1.8, проблема была решена.
Это может помочь вам :)
Ответ 7
У меня была эта проблема только в среде разработчиков. Решением этой проблемы было просто добавить несколько флагов, чтобы игнорировать SSL для ВМ:
-Ddeployment.security.TLSv1.1=false
-Ddeployment.security.TLSv1.2=false
Ответ 8
Поскольку это решение:
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
}
}
}
Джава
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("SSL");
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. Как уже упоминалось, игнорирование сертификатов не является хорошей идеей.
Ответ 9
Попробуйте следующее (просто поставьте его перед Jsoup.connect("https://example.com")
:
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
}
});