获取javax.net.ssl.SSLException:收到致命警报:使用Jsoup抓取数据时的protocol_version

时间:2015-11-08 14:26:23

标签: java ssl web-scraping jsoup

我正在尝试使用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();

请告诉我这里的错误。

2 个答案:

答案 0 :(得分:8)

您希望在此处使用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分析器,您定位的网站仅启用了以下密码套件:

Cipher Suites Enabled
Name  (ID)                                       Key Size (in bits)
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256  (0xC02F)  128   ECDH 256-bit (P-256) 
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384  (0xC030)  256   ECDH 256-bit (P-256) 
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256  (0x9E)      128   DH 2048-bit  
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384  (0x9F)      256   DH 2048-bit

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

最后的想法:

  

在安全方面,总是使用最新的更新版本。

答案 1 :(得分:3)

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

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

此外,使用全权信任TrustManager意味着几乎所有访问您网络的坏人都可以伪造此网站并公开您发送的任何敏感数据。最好设置本地信任库,使其接受您需要的证书和服务器,但不接受虚假的服务器。