天天看點

java https 請求 javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

最近聯調https接口時,請求https 一直報handshake_failure 握手失敗。在網上百度了幾天,驗證了很多方法,一直沒有解決我的問題。

我把我的解決方法,分析一下,供大家參考

http-nio-8084-exec-1, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

HTTPS 專用檢測工具網站

https://myssl.com/

HTTPS 安全評估、ATS 檢測、證書鍊補全工具、HTTP/2 支援檢測

解決方法1:設定https.protocols

System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,SSLv3");

設定輸出網絡日志

System.setProperty("javax.net.debug", "all");

然後看到下面的輸出:

0000: 16 03 03 00 89 01 00 00 85 03 03 5F 6A C2 08 7C ..........._j...

0010: A9 2A 33 9A C9 B7 D2 11 CA A4 49 2F CD CB 74 14 .*3.......I/..t.

0020: 09 BB 6F 4B 0C 7A 81 82 62 D1 7A 00 00 26 00 3D ..oK.z..b.z..&.=

0030: 00 6B 00 6A 00 35 00 39 00 38 00 3C 00 67 00 40 .k.j.5.9.8.<.g.@

0040: 00 2F 00 33 00 32 00 9D 00 9F 00 A3 00 9C 00 9E ./.3.2..........

0050: 00 A2 00 FF 01 00 00 36 00 0D 00 1C 00 1A 06 03 .......6........

0060: 06 01 05 03 05 01 04 03 04 01 04 02 03 03 03 01 ................

0070: 03 02 02 03 02 01 02 02 00 00 00 12 00 10 00 00 ................

0080: 0D 61 70 69 2E 39 39 35 31 32 30 2E 63 6E .api.995120.cn

0000: 15 03 03 00 02 .....

0000: 02 28 .(

http-nio-8084-exec-1, READ: TLSv1.2 Alert, length = 2

http-nio-8084-exec-1, RECV TLSv1.2 ALERT: fatal, handshake_failure

http-nio-8084-exec-1, called closeSocket()

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)

at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)

at java.lang.reflect.Constructor.newInstance(Constructor.java:423)

at sun.net.www.protocol.http.HttpURLConnection$10.run(HttpURLConnection.java:1950)

at sun.net.www.protocol.http.HttpURLConnection$10.run(HttpURLConnection.java:1945)

at java.security.AccessController.doPrivileged(Native Method)

at sun.net.www.protocol.http.HttpURLConnection.getChainedException(HttpURLConnection.java:1944)

at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1514)

at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1498)

at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:268)

at com.hipee.web.hour24ecg.controller.TestController.saveBinary(TestController.java:39)

at com.hipee.web.hour24ecg.controller.TestController.versionInfo(TestController.java:25)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

解決方法2:替換JCE包

因為我的伺服器是jdk8版本,下載下傳後解壓,可以看到local_policy.jar和US_export_policy.jar以及readme.txt,

替換${java_home}/jre/lib/security/ 下面的local_policy.jar和US_export_policy.jar即可

JDK7:

https://www.jianshu.com/go-wild?ac=2&url=https%3A%2F%2Fwww.oracle.com%2Ftechnetwork%2Fjava%2Fjavase%2Fdownloads%2Fjce-7-download-432124.html

JDK8:

https://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html

但我的jdk版本格式如上

[developer@143-196 security]$ pwd

/usr/java/jdk1.8.0_231/jre/lib/security

[developer@143-196 security]$ ll

total 160

-rw-r--r-- 1 10 143 4054 Oct 5 2019 blacklist

-rw-r--r-- 1 10 143 1273 Oct 5 2019 blacklisted.certs

-rw-r--r-- 1 10 143 100515 Oct 5 2019 cacerts

-rw-r--r-- 1 10 143 2466 Oct 5 2019 java.policy

-rw-r--r-- 1 10 143 44261 Oct 5 2019 java.security

-rw-r--r-- 1 10 143 98 Oct 5 2019 javaws.policy

drwxr-xr-x 4 10 143 38 Oct 5 2019 policy

-rw-r--r-- 1 10 143 0 Oct 5 2019 trusted.libraries

[developer@143-196 security]$ tree policy/

policy/

├── limited

│   ├── local_policy.jar

│   └── US_export_policy.jar

└── unlimited

├── local_policy.jar
└── US_export_policy.jar
           

因為從Java 1.8.0_151版本開始,java公司為JVM啟用無限制強度管轄政策,則不能使用AES-256。把java.security檔案的第826行的注釋去掉即可

crypto.policy=unlimited

重新啟動項目,還是失敗

linux伺服器錯誤日志:

keyStore is :

keyStore type is : jks

keyStore provider is :

init keystore

init keymanager of type SunX509

trigger seeding of SecureRandom

done seeding SecureRandom

Allow unsafe renegotiation: false

Allow legacy hello messages: true

Is initial handshake: true

Is secure renegotiation: false

http-nio-8084-exec-1, setSoTimeout(0) called

http-nio-8084-exec-1, the previous server name in SNI (type=host_name (0), value=api.995120.cn) was replaced with (type=host_name (0), value=api.995120.cn)

Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256 for TLSv1

Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 for TLSv1

Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 for TLSv1

Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256 for TLSv1.1

Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 for TLSv1.1

Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 for TLSv1.1

%% No cached client session

win本地環境正常日志

Allow unsafe renegotiation: true

qtp1971495275-19, setSoTimeout(0) called

qtp1971495275-19, the previous server name in SNI (type=host_name (0), value=api.995120.cn) was replaced with (type=host_name (0), value=api.995120.cn)

Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 for TLSv1

Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 for TLSv1

Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 for TLSv1

Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 for TLSv1

Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 for TLSv1.1

Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 for TLSv1.1

Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 for TLSv1.1

Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 for TLSv1.1

Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 for TLSv1.1

發現确實*SHA384

解決方法3:BouncyCastle配置

BouncyCastle是一款開源的密碼包,其中包含了大量的密碼算法,使用BouncyCastle的目的就是為了擴充算法支援

(1) 将bcprov-jdk15on-162.jar檔案導入相關工程

(2) 在需要使用加密的代碼中導入以下兩個類

import java.security.Security;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

(3) 在初始化密鑰工廠、密鑰生成器等引擎前調用如下代碼:

加入BouncyCastleProvider的支援

Security.add.addProvider(new BouncyCastleProviderrr());

或者使用以下方式

MessageDigest md = MessageDigest.getInstant("MD4","BC");

//每個提供者都有簡稱,Bouncy Castle提供者的簡稱為BC

<dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.66</version>
    </dependency>
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-ext-jdk15on</artifactId>
        <version>1.66</version>
    </dependency>
           

最終解決