Search code examples
javahandshakesslhandshakeexception

Java - Received fatal alert: handshake_failure


I'm trying to get an HTML source code of a site.

My code:

public static void main(String[] args) {
    URL url;
    InputStream is;
    try {
        url = new URL("https://www.trackobot.com/");
        is = url.openStream();
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

But, when run this code, I get an exception:

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
   at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
   at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
   at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2023)
   at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1125)
   at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
   at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
   at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
   at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
   at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
   at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1546)
   at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
   at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
   at java.net.URL.openStream(URL.java:1045)
   at JsoupTutorial.ConnectToUrl.main(ConnectToUrl.java:24)

If I change the site, it work well, even with https sites like PayPal. But, still I have some sites that it just don't work and throw that exception. This site in the example is one of those sites that it don't work.

I searched for it and understand that I need to import the certificate of this site to the Java keystore. Am I correct?

My question is how Chrome do manage to enter those "Secure" sites ang get the HTML code? someone has to update (import) the certificate to the Chrome Cer database..who do this and when it happen? (Just in case that i'm correct above).

Anyway, I'm want to manage to load those sites perfect and receive the data I want. Where can I learn it from the basic?

Thank you.


Solution

  • The issue here is almost certainly that you're trying to access a site which uses SSL/HTTPS, but you aren't using an API which supports that. You may try using HttpsURLConnection with a (bad) trust store which accepts everything. Don't ever do this in production.

    SSLContext ctx = SSLContext.getInstance("TLS");
    ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
    SSLContext.setDefault(ctx);
    
    URL url = new URL("https://www.trackobot.com/");
    HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
    con.setHostnameVerifier(new HostnameVerifier() {
        @Override
        public boolean verify(String arg0, SSLSession arg1) {
            return true;
        }
    });
    con.setRequestMethod("GET");
    System.out.println("Response Code : " + con.getResponseCode());
    
    BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
    String line;
    StringBuffer response = new StringBuffer();
    
    while ((line = in.readLine()) != null) {
        response.append(line);
    }
    in.close();
    
    System.out.println(response.toString());
    
    private static class DefaultTrustManager implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
    
        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
    
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }
    

    Ideally HttpsURLConnection out of the box should work fine assuming that the domain presents a certificate from a relatively standard provider. Since it doesn't work for your domain, we can configure it to trust everything. Bad in production, but maybe lets you proceed for the time being.