Получение javax.net.ssl.SSLException: получено фатальное предупреждение: protocol_version при очистке данных с помощью Jsoup

Я пытаюсь получить данные с сайта с помощью Jsoup. Ссылка на сайт находится здесь!

Вот мой код для получения данных. `

    // WARNING: do it only if security isn't important, otherwise you have 
    // to follow this advices: http://stackru.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 ответа

Решение

Вы хотите использовать 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

Наконец, я пошел к анализатору SSL Comodoca и увидел кое-что интересное. Согласно анализатору SSL, на сайт, на который вы нацелены, включены только следующие комплекты шифров:

Cipher Suites включен
Имя (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 бит

(см. полную информацию)

Со своей стороны, у меня нет ни одного из вышеуказанных апартаментов. Проверьте, есть ли они у вас:

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 на Java 8 (1.8.0_20), которые по умолчанию поддерживают TLS v1.2 и предоставляют необходимые наборы шифров.

Вот сокращенный список поддерживаемых комплектов шифров (всего 71 комплект) для Java 8 (1.8.0_20) в Windows 7.

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

Заключительная мысль:

Когда дело доходит до безопасности, ВСЕГДА используйте последнюю обновленную версию.

(Из комментария для закрытия, немного расширен для будущих искателей)

Экспериментально для этого сайта требуется версия протокола TLSv1.2, и хотя в Java7 JSSE это реализовано, на стороне клиента по умолчанию отключаются версии 1.2 и 1.1. Java8 включает их по умолчанию; или в Java7, так как Jsoup использует HttpsURLConnection Вы можете изменить включенные версии с системным свойствомhttps.protocols, Вам нужно включить хотя бы TLSv1.2 и для большей гибкости следует использовать все приемлемые в настоящее время протоколы https.protocols=TLSv1,TLSv1.1,TLSv1.2,

Кроме того, используя это все доверие TrustManager означает, что любой злоумышленник, имеющий доступ к вашей сети, может подделать этот сайт и раскрыть любые конфиденциальные данные, которые вы ему отправляете. Лучше установить локальное хранилище доверенных сертификатов, чтобы оно принимало сертификаты и, следовательно, серверы, которые вам нужны, но не поддельные.

Другие вопросы по тегам