如何使用jsoup通过https连接?

voj3qocg  于 2021-07-11  发布在  Java
关注(0)|答案(9)|浏览(740)

它在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();
}
ffscu2ro

ffscu2ro1#

如果您想以正确的方式进行,并且/或者只需要处理一个站点,那么您基本上需要获取有问题的站点的ssl证书并将其导入java密钥库。这将产生一个jks文件,在使用jsoup(或 java.net.URLConnection ).
您可以从webbrowser的商店获取证书。假设您使用的是firefox。
使用firefox访问有问题的网站,这就是你的情况https://web2.uconn.edu/driver/old/timepoints.php?stopid=10
在地址栏左侧,您将看到蓝色的“uconn.edu”(这表示有效的ssl证书)
点击查看详情,然后点击更多信息按钮。
在出现的安全性对话框中,单击查看证书按钮。
在出现的证书面板中,转到详细信息选项卡。
单击证书层次结构的最深项,在本例中是“web2.uconn.edu”,最后单击导出按钮。
现在你有一个 web2.uconn.edu.crt 文件。
接下来,打开命令提示符并使用 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请求

bn31dyow

bn31dyow2#

在我的例子中,我所需要做的就是在我的连接中添加.validateLSCertificates(false)

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

我还必须增加读取超时,但我认为这是无关紧要的

cotxawn7

cotxawn73#

我在这里和搜索中的链接问题中无意中找到了答案,并想添加两条信息,因为已接受的答案不适合我的非常类似的场景,但还有一个额外的解决方案,即使在这种情况下也适用(证书和主机名与测试系统不匹配)。
有一个github请求添加这样的功能。所以也许很快问题就会解决:https://github.com/jhy/jsoup/pull/343 编辑:github请求已解析,禁用证书验证的方法是:validatelscertificates(boolean validate)
基于http://www.nakov.com/blog/2009/07/16/disable-certificate-validation-in-java-ssl-connections/ 我找到了一个似乎可行的解决方案(至少在我的场景中,jsoup1.7.3被称为maven任务的一部分)。我用一种方法 Package 了它 disableSSLCertCheck() 在第一个jsoup.connect()之前调用。
在使用此方法之前,您应该真正了解您在那里所做的工作—不检查ssl证书是一件非常愚蠢的事情。始终为您的服务器使用正确的ssl证书,这些证书由公认的ca签名。如果您负担不起公认的ca,请使用正确的ssl证书,但上面有@balusc accepted answer。如果您无法配置正确的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);
    }
fcg9iug3

fcg9iug34#

要抑制特定jsoup连接的证书警告,可以使用以下方法:
Kotlin

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);
    }
  }

注意。如前所述,忽略证书不是一个好主意。

mccptt67

mccptt675#

我也有同样的问题,但采取了懒惰的路线-告诉你的应用程序忽略证书和进行无论如何。
我从这里得到了代码:如何在java中使用本地https url?
您必须导入这些类才能工作:

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;

只需在尝试建立连接之前运行该方法,瞧,不管发生什么,它都会信任cert。当然,如果你真的想确保证书是真实的,这是没有任何帮助的,但是对于监视你自己的内部网站等很好。

3hvapo4f

3hvapo4f6#

我不是这个领域的Maven,但我在尝试使用java.netapi通过https连接到网站时遇到了类似的异常。当您使用https访问站点时,浏览器会为您提供大量有关ssl证书的工作。但是,当您手动连接到站点(手动使用http请求)时,所有这些工作仍然需要完成。现在我不知道这些工作到底是什么,但它必须下载证书并把它们放在java可以找到它们的地方。这里有一个链接,希望能为你指明正确的方向。
http://confluence.atlassian.com/display/jira/connecting+to+ssl+services

x7rlezfr

x7rlezfr7#

我在使用jsoup时也遇到了同样的问题,我无法连接并获取https url的文档,但是当我将jdk版本从1.7更改为1.8时,问题得到了解决。
它可能会帮助您:)

1bqhqjot

1bqhqjot8#

我只在dev环境中遇到过这个问题。解决此问题的解决方案只是添加几个标志以忽略vm的ssl:

-Ddeployment.security.TLSv1.1=false 
-Ddeployment.security.TLSv1.2=false
8yoxcaq7

8yoxcaq79#

试着跟随(把它放在前面) Jsoup.connect("https://example.com") :

Authenticator.setDefault(new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(username, password.toCharArray());
        }
    });

相关问题