Today I encountered a Received fatal alert: handshake_failure problem in my project. The direct translation just failed. To be honest, this is the first time I have encountered this problem.In forums, in the sea of technical blogs, I still haven't solved my problem.It was unexpected that a final omission found the cause.
First of all, I would like to tell you some experiences and solutions on the Internet, which is a summary.
We can both send requests with curl and postman, and the handshake succeeds. Code alone cannot request success.handshake_failure is by no means a cause.
Reason 1: Protocol versions of Https are inconsistent.The protocols are TLSv1.2,TLSv1.1,SSLv3
How do I determine this?
1: If you are running locally, you can do this by writing a communications client (only for testing handshakes)
The code was temporarily quoted by me and I couldn't get it off the server.
import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ConnectException; import java.net.URL; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; public class HttpsTest { private static class TrustAnyTrustManager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } } private static class TrustAnyHostnameVerifier implements HostnameVerifier { public boolean verify(String hostname, SSLSession session) { return true; } } public static String sendHttps(String url) throws Exception { InputStream in = null; OutputStream out = null; String returnValue = ""; try { //SSLContext sc = SSLContext.getInstance("SSL"); // System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,SSLv3"); // SSLContext sc = SSLContext.getInstance("TLS", "SunJSSE"); SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom()); URL console = new URL(url); HttpsURLConnection conn = (HttpsURLConnection) console.openConnection(); conn.setSSLSocketFactory(sc.getSocketFactory()); // conn.setHostnameVerifier(new TrustAnyHostnameVerifier()); conn.setRequestMethod("POST"); conn.connect(); InputStream is = conn.getInputStream(); DataInputStream indata = new DataInputStream(is); returnValue = indata.readLine(); conn.disconnect(); } catch (ConnectException e) { e.printStackTrace(); throw e; } catch (IOException e) { e.printStackTrace(); throw e; } finally { try { in.close(); } catch (Exception e) { } try { out.close(); } catch (Exception e) { } } return returnValue; } public static void main(String[] args) throws Exception { System.out.println(sendHttps("https://finance-23055.beta.qunar.com")); } } ## Code reload https://blog.csdn.net/dzy_001/article/details/81012959
Then set it in the run parameters
-Djavax.net.debug=all
Then run, there will be the following, a lot of content, you can find these.
main, WRITE: TLSv1.2 Handshake, length = 191 ## This is the version sent by the client [Raw write]: length = 196 main, READ: TLSv1.2 Alert, length = 2 ## This is the version returned by the server main, RECV TLSv1.2 ALERT: fatal, handshake_failure
Unfortunately, this does not solve my problem because both client and server sides are TLSv1.2.If you find that the two versions are different, you are in this situation. How to solve this problem, please read other articles. I will not go into details and give two recommendations.
http://www.voidcn.com/article/p-xjnaqnwd-bqu.html
https://blog.csdn.net/u014644574/article/details/83381303
2: The server does not support this protocol
SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure //Then use openssl s_client -connect finance-23055.beta.qunar.com:443 -state -debug -tls1 -msg //The message reply you see is like this: read from 0xb644fc0 [0xb689760] (5 bytes => 5 (0x5)) 0000 - 15 03 01 00 02 ..... read from 0xb644fc0 [0xb689765] (2 bytes => 2 (0x2)) 0000 - 02 28 //Where 0x15 represents alert and 0x28 represents handshake failure
This makes it difficult to discover the server's support protocol, slow, guessed, and possibly unsure
https://www.ssllabs.com/ssltest/
Enter this address and enter the server address you want to test.Then a report will come out, very detailed.
The agreement makes it clear whether it is supported or not.There are more details below. Try it yourself.
3:SSL algorithm not supported
curl -d "" -k https://IP:port/tests -v
Using the above commands, we can clearly see the execution process.
One of the lines looks like this
SSL connection using ******** ## *Represents the algorithm used by curl
This algorithm is ours.Let's see if our program supports this algorithm?
ctx.getSupportedSSLParameters().getCipherSuites() ctx.getSocketFactory().getDefaultCipherSuites() ctx.getSocketFactory().getSupportedCipherSuites() ## ctx is an SSLContext object
Print it out to see if curl's algorithm is supported in our java.
See: https://blog.csdn.net/qq_36783371/article/details/80665901
4: That's me, the saddest one.Look at my code above, if you remove this section, you won't fail to shake hands.This verification is also within the handshake process.
private static class TrustAnyHostnameVerifier implements HostnameVerifier { public boolean verify(String hostname, SSLSession session) { return true; } }
Okay, that's all I've summarized.