【问题标题】:Server closes connections made using httpclient and Java 7服务器关闭使用 httpclient 和 Java 7 建立的连接
【发布时间】:2017-03-07 08:07:50
【问题描述】:

我正在尝试连接到使用 SNI 提供证书的远程服务器。我注意到,当我使用 Java 7 编译和运行代码而不是通过 Java 8 编译和运行它时,服务器正在关闭连接。

以下是我为测试此假设而编写的代码。我切换 Java 版本并运行代码并得到不同的结果。

public static void getRequest() throws IOException, NoSuchAlgorithmException, KeyManagementException {
    String url = "https://sorry i can not share the exact url because of privacy concerns";

    HttpClient client = getClientInstance();
    HttpGet request = new HttpGet(url);

    HttpResponse response = client.execute(request);

    System.out.println("Response Code : "
            + response.getStatusLine().getStatusCode());

    BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));

    StringBuffer result = new StringBuffer();
    String line = "";
    while ((line = rd.readLine()) != null) {
        result.append(line);
    }
    System.out.println("####### the result is");
    System.out.println(result.toString());
}

private static org.apache.http.client.HttpClient getClientInstance() throws KeyManagementException, NoSuchAlgorithmException {
    RequestConfig defaultRequestConfig = RequestConfig.copy(RequestConfig.DEFAULT)
            .setConnectTimeout(60 * 1000)
            .setSocketTimeout(60 * 1000)
            .setConnectionRequestTimeout(60 * 1000)
            .build();

    return HttpClientBuilder.create().setDefaultRequestConfig(defaultRequestConfig).build();
}

有人遇到过这样的问题并解决了吗?我知道最终的解决方法是使用 Java 8,但这不是我可以在当前时间限制内完成的任务,因为我正在调试的整个代码库非常庞大,并且具有可能不适用于 Java 7 的依赖项。

抛出的异常如下;

*** ClientHello, TLSv1
RandomCookie:  GMT: 1472095425 bytes = { 254, 51, 194, 246, 77, 6, 185, 8, 224, 187, 85, 225, 133, 128, 122, 1, 245, 13, 230, 239, 156, 93, 164, 184, 251, 159, 111, 60 }
Session ID:  {}
Cipher Suites: [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_AES_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_WITH_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_WITH_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_128_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, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension server_name, server_name: [host_name: lasclev.org]
***
main, WRITE: TLSv1 Handshake, length = 169
main, handling exception: java.net.SocketException: Connection reset
main, SEND TLSv1 ALERT:  fatal, description = unexpected_message
main, WRITE: TLSv1 Alert, length = 2
main, Exception sending alert: java.net.SocketException: Broken pipe
main, called closeSocket()
java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:196)
    at java.net.SocketInputStream.read(SocketInputStream.java:122)
    at sun.security.ssl.InputRecord.readFully(InputRecord.java:442)
    at sun.security.ssl.InputRecord.read(InputRecord.java:480)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:934)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1332)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1359)

下面还有我之前进行的 SSL Labs 测试的屏幕截图。

【问题讨论】:

    标签: java java-8 java-7 apache-httpclient-4.x sni


    【解决方案1】:

    您没有显示 SSLLabs 报告中列出支持的协议的部分,但我敢打赌,您会发现此服务器仅支持 TLSv1.2 或者可能支持 TLSv1.2 和 TLSv1.1,但不支持 TLSv1.0。特别是,处理受 PCI DSS 约束的支付交易的系统通常被禁止使用 TLSv1.0(又名“早期 TLS”),这显然是由于对 BEAST 反应过度(尽管它不值得,但在 NVD 中仍然是 4.3)。尽管在这种情况下,服务器应该发出警报 70 或者可能是 71 或 40 而不仅仅是重置(或关闭)。 Java7 (JSSE) 客户端默认不执行 TLSv1.2 或 TLSv1.1。

    这可能取决于 HttpClient 的版本——我有 4.5——但我认为你可以:

    • 为它创建一个适当配置的SSLConnectionSocketFactory.setSSLSocketFactory,或者

    • .useSystemProperties(true) 并根据需要设置 sysprop https.protocolsTLSv1.2TLSv1.1,TLSv1.2(也被 javax.net.HttpsURLConnection 使用),但这可能会影响您不想要的其他东西(请参阅 javadoc useSystemProperties)

    【讨论】:

    • 你的建议完全有道理,但它对我不起作用。远程服务器是我无法控制的。由于时间限制,我通过Runtime.getRuntime().exec 使用 curl 对此做了一个讨厌的解决方法
    猜你喜欢
    • 1970-01-01
    • 2020-05-11
    • 2013-08-11
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    • 1970-01-01
    • 2013-04-10
    • 1970-01-01
    相关资源
    最近更新 更多