【问题标题】:javax.net.ssl.SSLException: Received close_notify during handshake error when sending request from Apache Tomcat 9.0.54javax.net.ssl.SSLException:从 Apache Tomcat 9.0.54 发送请求时,在握手错误期间收到 close_notify
【发布时间】:2022-01-04 10:19:40
【问题描述】:

我已将我的网站从一台非常旧的服务器移至支持 SSL 的新服务器,并从 Apache Tomcat 6 升级到 Apache Tomcat 9.0.54。现在,当我的服务器上运行的代码尝试使用此代码向 trustspot 服务器(受信任的评论站点)发送请求时

    try
    {
        HttpClient httpclient = new DefaultHttpClient();
    
        this.order=order;
        String dataForHmac      = MERCHANT_ID + order.getOrderId() + order.getCustomerEmail();
        String calculatedHmac   = base64sha256(dataForHmac, SECRET_KEY);
        order.setHmac(calculatedHmac);
        order.setKey(API_KEY);
    
        Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).setPrettyPrinting().create();
        System.out.println(gson.toJson(order));
    
        String jsonData = gson.toJson(order);
    
        url = new URL("https://trustspot.io/api/pub/new_order_product");
        httpMethod = new HttpPost(url.toExternalForm());
        httpMethod.addHeader("Content-Type", "application/json");
        StringEntity se = new StringEntity(jsonData);
        httpMethod.setEntity(se);
        HttpResponse httpResponse = httpclient.execute(httpMethod);
        InputStreamReader is = new InputStreamReader(httpResponse.getEntity().getContent());
        BufferedReader rd;
        rd = new BufferedReader(is);
    
        String line = "";
        while ((line = rd.readLine()) != null)
        {
            System.out.println(line);
        }
    }
    catch(Exception ex)
    {
        StringWriter messageBody = new StringWriter();
        PrintWriter pw = new PrintWriter(messageBody);
        ex.printStackTrace(pw);
        Email.sendAlert("Unable to send trustpot review request:"+ order.getCustomerEmail(), messageBody.toString());
    }

我明白了

javax.net.ssl.SSLException: Received close_notify during handshake 

我该如何解决这个问题?

    javax.net.ssl.SSLException: Received close_notify during handshake
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1959)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1911)
        at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2012)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1135)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397)
        at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:553)
        at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:412)
        at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:179)
        at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:328)
        at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:612)
        at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:447)
        at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:884)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
        at com.jthink.store.trustspot.TrustSpotProductRequest.sendRequest(TrustSpotProductRequest.java:68)
        at com.jthink.store.googleprocess.AbstractCreateAndSendLicense.requestReview(AbstractCreateAndSendLicense.java:306)
        at com.jthink.store.googleprocess.CreateAndSendSongKongLicense.createAndSendLicense(CreateAndSendSongKongLicense.java:120)
        at com.jthink.store.action.VerifyPaymentEJunkie.processEachItem(VerifyPaymentEJunkie.java:169)
        at com.jthink.store.action.VerifyPaymentEJunkie.handleRequest(VerifyPaymentEJunkie.java:82)
        at com.jthink.store.JThinkStoreServlet.doGet(JThinkStoreServlet.java:45)
        at com.jthink.store.JThinkStoreServlet.doPost(JThinkStoreServlet.java:32)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)

我正在使用 Java 1.8.0_161-b12

在设置-Dhttps.protocols=TLSv1-Dhttps.protocols=TLSv1.1, TLSv1.2 后尝试重新启动Tomcat,但没有任何区别

更新 在类中添加了一个 main(),所以现在我可以在 tomcat 之外的机器上运行测试,它以完全相同的方式失败

java -classpath classes:lib/*  com.jthink.store.trustspot.TrustSpotProductRequest -Dhttps.protocols=TLSv1

给出同样的例外

javax.net.ssl.SSLException: Received close_notify during handshake

在我的电脑上运行完全相同的代码可以正常工作。

更新 2

-Djavax.net.debug=ssl:handshake

trigger seeding of SecureRandom
done seeding SecureRandom
main, setSoTimeout(0) called
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
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
*** ClientHello, TLSv1.2
RandomCookie:  GMT: 1621095199 bytes = { 214, 189, 173, 184, 228, 255, 156, 82, 153, 122, 143, 245, 185, 144, 166, 172, 32, 10, 144, 123, 158, 248, 38, 4, 84, 67, 13, 79 }
Session ID:  {}
Cipher Suites: [TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA256withDSA, SHA224withECDSA, SHA224withRSA, SHA224withDSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA
Extension extended_master_secret
Extension server_name, server_name: [type=host_name (0), value=trustspot.io]
***
main, WRITE: TLSv1.2 Handshake, length = 146
main, READ: TLSv1.2 Alert, length = 2
main, RECV TLSv1.2 ALERT:  warning, close_notify
main, SEND TLSv1.2 ALERT:  fatal, description = unexpected_message
main, WRITE: TLSv1.2 Alert, length = 2
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLException: Received close_notify during handshake
main, called close()
main, called closeInternal(true)

在我的 PC 上,我看到的区别是它也有扩展 elliptic_curves 和扩展 ec_point_formats,我需要它们吗?

握手的长度也不同。

Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, secp384r1, secp521r1, sect283k1, sect283r1, sect409k1, sect409r1, sect571k1, sect571r1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA256withDSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA
Extension extended_master_secret
Extension server_name, server_name: [type=host_name (0), value=trustspot.io]
***
main, WRITE: TLSv1.2 Handshake, length = 214
main, READ: TLSv1.2 Handshake, length = 91

【问题讨论】:

  • (1) -Dsysprop=value 与其他 JVM 选项一样,只有在 java 命令上的主类名称(或 -jar 或 -m/--module)之前给出时才有效;但是(2)https.protocols 无论如何通常不会影响 Apache HttpClient,只有javax.net.ssl.HttpsURLConnection 和(3)如果确实如此,TLSv1(意思是 1.0)根本没有帮助,因为该服务器只接受 1.2 和 1.3,不低。 (4) 可能是 SNI;尝试使用-Djavax.net.debug=ssl:handshake 运行(在主类之前!),看看你的client-hello 是否有(正确的)server_name。
  • 谢谢,好的,将输出的末尾添加到问题中,(也移动了 tls 选项的位置并尝试了一些选项,但正如你所说的没有区别)
  • 我的服务器不支持某些密码套件,是不是我没有服务器支持的任何密码套件?
  • @dave_thompson_085 在我的 PC 上,我可以看到的区别是它也有扩展 elliptic_curves 和扩展 ec_point_formats,我需要它们吗?握手的长度也不同。
  • 确切地说,您的 first=bad 案例没有任何使用椭圆曲线的套件(ECDH[E] 或 ECDSA,对于 1.2),所以是的,这是个问题 因为that server only supports ECHDE (actually ECDHE_RSA) suites for 1.2。 Java 8应该支持 EC,除非你的 JVM 配置很奇怪或者你在 RedHat 系列(包括 Fedora CentOS 等)上使用了几年前的 OpenJDK,因为直到最近 RedHat 删除了 EC。否则,请查看 JRE/lib/security/java.security 并查看 SunEC 是否在提供者列表中。

标签: java ssl tomcat


【解决方案1】:

问题出在我的 Java 版本上,(答案来自@dave_thompson_085 评论,我不完全理解细节,如果没有完全正确解释,请见谅)

我在linux centos机器上使用Java 1.8.0_161-b12,结果这个版本不支持TLS 1.2的椭圆曲线套件,但我连接的服务器只支持ECHDE,这需要使用椭圆曲线算法所以因此不会起作用。

更新到 jdk1.8.0_202 并且现在可以工作了

【讨论】:

    【解决方案2】:

    一般 SSL 问题与证书问题有关,您确定您的旧证书仍然有效且配置正确吗?如果不是,我建议先将其添加到服务器中

    【讨论】:

    • 我的 SSL 证书很好(您可以通过访问我的网站jthink.net 的 SSL 版本进行检查)。但无论如何,在这种情况下它不是无关紧要的,因为我的服务器充当客户端与 trustpot 服务器对话,而且在我的代码中,我什至没有提到 SSL,因为它是相同的代码,我什至在我的旧服务器上没有 SSL 证书。
    • 好的,在进一步通知我可以看到 close_notify 问题。 javax.net.ssl.SSLException:在握手期间收到 close_notify 表示 ssl 连接的终止。此问题可能取决于机器的性能和网络问题。
    • 机器上没有发生什么事情,这不是性能问题
    • 添加了 SSLContext.getDefault().getSupportedSSLParameters().getProtocols()) 并得到了输出 SSLv2Hello SSLv3 TLSv1 TLSv1.1 TLSv1.2,我在某处读到可能存在一些关于服务器的 TLS 版本的问题(即信任端)支持,不知道如何进行。
    • 我使用的是 Java 1.8.0_161-b12
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-03
    • 2017-03-22
    • 1970-01-01
    • 2019-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多