2011-10-12 77 views
15

它的正常工作通过HTTP,但是当我尝试使用HTTPS源,它抛出以下异常:如何使用Jsoup通过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(); 
} 

回答

44

如果你想要做正确的方式,和/或需要处理只有一个网站,那么你基本上需要获取相关网站的SSL证书,并在其导入您的Java密钥存储。这将导致JKS文件在使用Jsoup(或java.net.URLConnection)之前又被设置为SSL信任存储。

您可以从Web浏览器的商店获取证书。假设您使用的是Firefox。

  1. 转到使用Firefox有问题的网站,这是你的情况https://web2.uconn.edu/driver/old/timepoints.php?stopid=10
  2. 在地址栏左侧你会看到蓝色的“uconn.edu”(这表明有效的SSL证书)
  3. 点击它查看详细信息,然后点击更多信息按钮。
  4. 在出现的安全对话框中,单击查看证书按钮。
  5. 在出现的证书面板中,转到详细信息选项卡。
  6. 单击证书层次结构中最深的项目,在本例中为“web2.uconn.edu”,最后单击导出按钮。

现在您已有web2.uconn.edu.crt文件。

接下来,打开命令提示符,然后在使用keytool命令的Java密钥库导入(它是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文件。

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(); 
// ... 

作为一个完全不同的选择,特别是当你需要处理多个站点(即你正在创建一个世界范围的网络爬虫:您可以如下终于在连接之前将其设置为SSL信任库),那么你还可以指示Jsoup(基本上,java.net.URLConnection)盲目信任所有SSL证书。另请参阅“处理不可信或错误配置的HTTPS站点”一节:Using java.net.URLConnection to fire and handle HTTP requests

+0

刚刚发现这个问题......我有同样的问题,但我怎么与CRT文件做,如果我我使用的Eclipse?什么是keytool的替代日食? – gedo

+0

显然,firefox允许使用域级证书来访问子域。但是,JSoup不会允许这样做。任何建议来解决这个问题? – bvdb

+0

感谢您的提示!加载.jdk文件仍然存在问题..看起来它不包含在外部/ crt目录中或不可访问。文件f =新文件(Environment.getRootDirectory()+“/crt/www.loterie.lu.jks”);如果(f.isFile()) \t \t \t Log.i(“JSOUP”,“找到证书文件”); \t \t else \t \t \t Log.i(“JSOUP”,“ERROR:Certificate file not found”+ f.getAbsolutePath()); – Dax

0

我在这个领域没有专家但在尝试使用java.net API通过HTTPS连接到网站时遇到了类似的异常。当您使用HTTPS访问网站时,浏览器会为您提供有关SSL证书的大量工作。但是,当您手动连接到网站(手动使用HTTP请求)时,所有这些工作仍需完成。现在我不知道这些工作究竟是什么,但它与下载证书并将它们放在Java可以找到它们的地方有关。这里有一个链接,希望能指引你正确的方向。

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

2

我有同样的问题,但采取了懒惰的路线 - 告诉您的应用程序忽略证书并继续进行。

我从这里代码:How do I use a local HTTPS URL in 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; 

只要运行该方法的地方尝试建立连接之前,瞧,无论如何,它只是相信证书。当然,这不是,如果你真的想使任何帮助确保证书是真实的,但良好的监控自己的内部网站等

7

我绊倒的答案在这里,并在链接的问题在我的搜索,并且希望添加两条信息,作为公认的答案不适合我的颇为相似的情况,但有适合即使在这种情况下,(证书和主机名不匹配测试系统)的附加解决方案。

  1. 有一个github请求来添加这样的功能。因此,也许很快就可以解决问题:https://github.com/jhy/jsoup/pull/343 编辑:Github的请求被解决,禁用证书验证的方法是:基于http://www.nakov.com/blog/2009/07/16/disable-certificate-validation-in-java-ssl-connections/
  2. validateTLSCertificates(布尔生效),我发现这似乎工作(至少在一个解决方案我场景,其中jsoup 1.7.3被称为maven任务的一部分)。我的方法中disableSSLCertCheck()我称之为非常第一Jsoup.connect()之前包裹它。

在使用此方法,你应该真正确保你明白你在那里做什么 - 不检查SSL证书是一个非常愚蠢的事情。对于由普遍接受的CA签署的服务器,始终使用正确的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); 
    } 
+0

对于接下来的读者...要小心:这会改变应用程序中任何类的行为,这会创建HttpsURLConnection的实例,而不仅仅是在运行它的类中。 – exoddus

+0

如何将此解决方案与Jsoup.connect(httpsurl).get()方法集成? – Luke

-3

尝试以下(只是把它Jsoup.connect("https://example.com")前:

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

在我的情况下,所有我需要做的就是在我的连接添加.validateTLSCertificates(假)

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

我也不得不增加读取超时,但我认为这是无关紧要的

0

我正面临与Jsoup相同的问题,我无法连接并获取https url的文档,但是当我将JDK版本从1.7更改为1.8时,问题得到解决。

它可以帮助你:)

相关问题