【问题标题】:getting javax.net.ssl.SSLException: Received fatal alert: protocol_version while scraping data using Jsoup获取 javax.net.ssl.SSLException:收到致命警报:protocol_version 使用 Jsoup 抓取数据时
【发布时间】:2016-02-09 06:23:35
【问题描述】:

我正在尝试使用 Jsoup 从网站获取数据。 该网站的链接是Click here

这是我获取数据的代码。 `

    // WARNING: do it only if security isn't important, otherwise you have 
    // to follow this advices: http://stackoverflow.com/a/7745706/1363265
    // Create a trust manager that does not validate certificate chains
    TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager(){
        public X509Certificate[] getAcceptedIssuers(){return null;}
        public void checkClientTrusted(X509Certificate[] certs, String authType){}
        public void checkServerTrusted(X509Certificate[] certs, String authType){}
    }};

    // Install the all-trusting trust manager
    try {
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (Exception e) {
        ;
    }`

String url = "https://www.sos.nh.gov/corporate/soskb/SearchResults.asp?FormName=CorpNameSearch&Words=Starting&SearchStr="+query+"&SearchType=Search"; Connection.Response response = Jsoup.connect(url).timeout(30000) .method(Connection.Method.GET) .userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0")
.execute(); Document document = response.parse();

请告诉我我的错误是什么。

【问题讨论】:

  • 网站使用哪些密码?您使用哪个 Java 版本?可能是站点需要 sslv3 而您的 Java 已移除支持
  • java版本是7。哪个版本的Java会支持呢?或者任何第三方库都应该这样做?
  • 您必须检查该 Web 服务器支持哪个 Ssl / tls 版本。可能是您要求的超出了它的支持范围。谷歌如何使用 OpenSSL 来获取这些信息,我相信你会在 stackoverflow 上找到信息。
  • @Marged + Subhasish:其他方式:该站点仅接受 TLSv1.2,Java7 客户端默认不支持 1.2(或 1.1)。由于Jsoup使用HttpsURLConnection,如果不能升级到Java8,可以设置系统属性https.protocols=TLSv1,TLSv1.1,TLSv1.2。此外,使用完全信任的 TrustManager 意味着几乎任何有权访问您的网络的人都可以伪造该站点并暴露您发送给它的任何敏感数据。
  • @dave_Thompson_085 我只是在猜测,很好,你检查了细节。想把它变成答案吗?

标签: java ssl web-scraping jsoup


【解决方案1】:

您想在此处使用 Java 8,因为它默认支持 TLSv1.2 以及其他必需的密码套件。

为什么不用 Java 7?

我在我的机器上使用 Java 7 (1.7.0_45) 进行了测试,得到了同样的错误。

我激活了调试消息并强制使用 TLSv1.2。

System.setProperty("javax.net.debug", "all");
System.setProperty("https.protocols", "TLSv1.2");

然后我遇到了这个新错误:

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

最后,我去了Comodoca's SSL analyzer,看到了一些有趣的东西。 根据 SSL 分析器,您所针对的网站仅启用了以下密码套件:

启用密码套件 名称 (ID) 密钥大小(以位为单位) TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xC02F) 128 ECDH 256 位 (P-256) TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xC030) 256 ECDH 256 位 (P-256) TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x9E) 128 DH 2048 位 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x9F) 256 DH 2048 位

(见Full details

就我而言,我没有上述任何套房。检查您是否拥有它们:

SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, null, new java.security.SecureRandom());

String[] scs = sc.getSocketFactory().getSupportedCipherSuites();
Arrays.sort(scs);

for(String s : scs) {
   System.out.println(s);
}

请参阅SSLSocketFactoryEx 以启用所需的密码套件。

为什么选择 Java 8?

另一方面,我通过从 Java 7 迁移到默认支持 TLS v1.2 并提供所需密码套件的 Java 8 (1.8.0_20) 成功运行了代码。

这是 Windows 7 上 Java 8 (1.8.0_20) 支持的密码套件(总共 71 个套件)的精简列表。

TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
...
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

片段

try {
    // 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(java.security.cert.X509Certificate[] certs, String authType) {
        }

        public void checkServerTrusted(java.security.cert.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());

    // Fetch url
    String url = "https://www.sos.nh.gov/corporate/soskb/SearchResults.asp?FormName=CorpNameSearch&Words=All&SearchStr=facebook&SearchType=Search";

    Connection.Response response = Jsoup //
            .connect(url) //
            .timeout(60000) //
            .method(Connection.Method.GET) //
            .userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0") //
            .execute();

    Document document = response.parse();
    System.out.println(document);
} catch (Exception e) {
    e.printStackTrace();
}

最后的想法:

在安全方面,始终使用最新的更新版本。

【讨论】:

  • 能否请您在答案中添加一个小sn-p,以便我接受。
  • @Subhasish 我在帖子中添加了一个 sn-p。
【解决方案2】:

(来自结束的评论,为未来的发现者扩展了一点)

通过实验,该站点需要协议版本 TLSv1.2,尽管 Java7 JSSE 实现了这一点,但客户端默认禁用 1.2 和 1.1。 Java8 默认启用它们; 或在 Java7 中,因为 Jsoup 使用 HttpsURLConnection,您可以使用 系统属性 https.protocols 更改启用的版本。您至少需要包含TLSv1.2,并且为了获得最大的灵活性,应该使用所有当前可接受的协议https.protocols=TLSv1,TLSv1.1,TLSv1.2

此外,使用完全信任的TrustManager 意味着几乎任何可以访问您网络的坏人都可以伪造该站点并暴露您发送给它的任何敏感数据。最好设置您的本地信任库,以便它接受您需要的证书和服务器,而不是伪造的。

【讨论】:

  • 由于某种原因,这不再适用于 java 7
猜你喜欢
  • 2013-05-08
  • 1970-01-01
  • 2016-06-12
  • 1970-01-01
  • 2018-02-16
  • 2017-03-22
  • 1970-01-01
  • 1970-01-01
  • 2019-09-02
相关资源
最近更新 更多