web-dev-qa-db-ja.com

javax.net.ssl.SSLExceptionの取得:致命的なアラートを受信しました:Jsoupを使用してデータをスクレイピング中にprotocol_version

Jsoupを使用してサイトからデータを取得しようとしています。サイトへのリンクは ここをクリック

これがデータをフェッチするための私のコードです。 `

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

ここで私の間違いを教えてください。

6
graphics123

ここでは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のSSLアナライザー に行って、何か面白いものを見ました。 SSLアナライザーによると、ターゲットとするサイトは次の暗号スイートのみを有効にしています。

暗号スイートが有効
名前(ID)キーサイズ(ビット単位)
 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(0xC02F)128 ECDH 256ビット(P-256)
 TLS_ECDHE_A_ )256 ECDH 256ビット(P-256)
 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256(0x9E)128 DH2048ビット
 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?

一方、デフォルトでTLSv1.2をサポートするJava 7からJava 8(1.8.0_20)に移動することで、コードの実行に成功しました。必要な暗号スイートを提供します。

これは、Windows7で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();
}

最終的な考え:

セキュリティに関しては、[〜#〜]常に[〜#〜]最新の更新バージョンを使用してください。

9
Stephan

(閉鎖のコメントから、将来の発見者のために少し拡大)

実験により、そのサイトにはプロトコルバージョンTLSv1.2が必要であり、Java7 JSSEはこれを実装していますが、クライアント側はデフォルトで無効1.2および1.1です。 Java8デフォルトでそれらを有効にします。 またはJava7では JsoupはHttpsURLConnectionを使用するため、有効なバージョンをシステムプロパティhttps.protocolsで変更できます。少なくともTLSv1.2を含める必要があり、最大限の柔軟性を得るには、現在受け入れ可能なすべてのプロトコルhttps.protocols=TLSv1,TLSv1.1,TLSv1.2を使用する必要があります。

また、そのすべてを信頼するTrustManagerを使用すると、ネットワークにアクセスできるほとんどすべての悪意のあるユーザーがこのサイトを偽造し、送信した機密データを公開する可能性があります。ローカルのトラストストアを設定して、証明書、つまり必要なサーバーを受け入れるようにすることをお勧めしますが、偽のトラストストアは受け入れません。

3