Java SSL SSLHandshakeException 握手失败

4
我正在使用Java 8,并使用SSLSocket请求以下网址:https://www.flixbus.de/sites/default/files/6_jetzt_buchen_button_tiny.png,但总是遇到握手错误。尝试使用socket.setEnabledProtocols()强制使用特定协议也没有帮助。顺便说一下,所有其他Web服务器都能正常工作,因此问题可能与我的代码无关。这个错误即使没有任何SSL/TLS协议限制也会发生。您有什么想法?使用选项“javax.net.debug = all”的输出如下:
DEBG getSecureScocket: Supported protocols:
- SSLv2Hello
- SSLv3
- TLSv1
- TLSv1.1
- TLSv1.2
DEBG getSecureScocket: Enabled protocols:
- TLSv1.2
Http Client, setSoTimeout(120000) called
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false

%% No cached client session
*** ClientHello, TLSv1.2
RandomCookie:  GMT: 1426330417 bytes = { 229, 161, 185, 11, 136, 85, 35, 88, 166, 144, 191, 126, 10, 196, 215, 241, 43, 190, 221, 246, 240,
217, 82, 29, 180, 106, 35, 253 }
Session ID:  {}
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_
AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH
_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_A
ES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WIT
H_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WIT
H_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_12
8_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1,
secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r
2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA25
6withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA
***
[write] MD5 and SHA1 hashes:  len = 193
[Raw write]: length = 198
[Raw read]: length = 5
[Raw read]: length = 2
Http Client, READ: TLSv1.2 Alert, length = 2
Http Client, RECV TLSv1.2 ALERT:  fatal, handshake_failure
Http Client, called closeSocket()
Http Client, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Http Client, called close()
Http Client, called closeInternal(true)
Http Client, called close()
Http Client, called closeInternal(true)

Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
        at sun.security.ssl.Alerts.getSSLException(Unknown Source)
        at sun.security.ssl.Alerts.getSSLException(Unknown Source)
        at sun.security.ssl.SSLSocketImpl.recvAlert(Unknown Source)
        at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
        at sun.security.ssl.SSLSocketImpl.writeRecord(Unknown Source)
        at sun.security.ssl.AppOutputStream.write(Unknown Source)
        at java.io.OutputStream.write(Unknown Source)
        [...]

你尝试过启用所有支持的协议而不仅仅是TLSv1.2吗?只是为了看看是否存在问题(因为正如你可能已经知道的那样,SSLvX不再推荐在生产中使用)。 - morgano
是的。首先我使用了默认设置,启用了所有协议。也不起作用。 我在这里找到了解决方案(https://dev59.com/nG445IYBdhLWcg3w0dZD#4686924)。这就是为什么我限制了协议并希望它能有所帮助。 - Enzo Matrix
2个回答

6
该网站需要SNI(服务器名称指示),也就是说,如果没有SNI,则握手将失败。所有现代浏览器都支持SNI,但并非所有编程语言中的SSL堆栈都支持SNI或默认使用它。请参见http://www.vimino.com/2014/01/jep-114-tls-sni-extension-sunjsse-behavior-changes/,了解如何在Java 8中使用SNI。
您可以使用openssl s_client检查此类行为:
# without SNI
$ openssl s_client -connect www.flixbus.de:443
CONNECTED(00000003)
140612985652896:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
....
New, (NONE), Cipher is (NONE)

# with SNI
$ openssl s_client -connect www.flixbus.de:443  -servername 'www.flixbus.de'
CONNECTED(00000003)
...
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256

或者您可以使用 analyze.pl

$ perl analyze-ssl.pl  www.flixbus.de
-- www.flixbus.de port 443
 * maximum SSL version  : TLSv1_2 (SSLv23)
 ...
 * SNI supported        : SSL upgrade fails without SNI

非常感谢您指出这个(新的)SNI扩展。这真正解决了问题。 - Enzo Matrix
@steffen-ullrich 你好,如果我运行你的脚本,会得到 IO::Socket::SSL version 1.984 required--this is only version 1.31 at analyze-ssl.pl line 10. 的错误提示。对于非 Perl 用户有什么建议吗? - injecteer
@injecteer:你使用的1.31版本已经超过5年了,所以我猜你需要获取一个更新的版本。如果你在Windows上,最新的Strawberry Perl应该包含你需要的内容。如果你在Linux上,大多数最近的发行版都包含你需要的内容。 - Steffen Ullrich
你是如何确定这个网站需要SNI的? - heez
1
@heez:使用我在答案中提到的工具。但你也可以使用SSLLabs - Steffen Ullrich

0

这个错误可能是因为你使用的Tls1.2服务器不支持


我限制使用TLS1.2,因为服务器响应的是TLS1.2。至少从日志中我理解是这样的。 如果我不进行任何协议限制,它也无法工作。 - Enzo Matrix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接