SSL连接重置

35

我正在尝试在Java中连接到一个HTTPS端点。我尝试过的每种方法(更多细节请参见下文)最终都会生成此堆栈跟踪:

java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:168)
at com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:293)
at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:331)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:798)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:753)
at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:75)

我已尝试:

  • 使用javax SOAP库和new URL("https://...")进行连接
  • 使用new URL("https://...").openConnection()进行连接
  • 手动创建SSL连接:

            Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
    
        SSLSocket socket = (SSLSocket) factory.createSocket("...", 443);
    
        Writer out = new OutputStreamWriter(socket.getOutputStream());
        // https requires the full URL in the GET line
        //
        out.write("GET / HTTP/1.0\r\n");
        out.write("\r\n");
        out.flush();
    
        // read response
        BufferedReader in = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()));
        int c;
        while ((c = in.read()) != -1) {
            System.out.write(c);
        }
    
        out.close();
        in.close();
        socket.close();
    
    一些更多的细节:
    - 我已经尝试过的每一种方法都可以用于其他SSL服务器,只有这个特定的服务器出现问题(我没有权利讨论什么服务器,它是一个商业合作伙伴) - 我可以用web浏览器和curl模拟的SOAP请求连接到这个服务器;这是特定于Java的问题。
    因此,似乎很明显Java和HTTPS服务器之间存在一些争议,可能意味着服务器具有一些奇怪的SSL配置。然而,我无法直接访问服务器,而且掌控服务器的人距离我很远,由于非常不同的时区,交流有点紧张。
    如果我的假设正确,可能会出现什么SSL问题?什么可能引起这样的问题?我在哪里可以要求控制服务器的人查找问题?当我使用curl进行请求时,我收到了这些服务器配置头:
    Server: Apache/2.2.9 (Debian) mod_jk/1.2.26 PHP/5.2.6-1+lenny10 with Suhosin-Patch mod_ssl/2.2.9 OpenSSL/0.9.8g mod_perl/2.0.4 Perl/v5.10.0
    X-Powered-By: PHP/5.2.6-1+lenny10
    X-SOAP-Server: NuSOAP/0.7.3 (1.114)
    

在我的代码中发生的位置取决于我使用的方法。它总是发生在out.flush()或开始读取连接时。但我包含的部分始终相同 - 问题在某个时候出现在握手过程中。 - roguenet
1
@Nathan:你应该回答自己的问题并接受你的答案。虽然你不会得到任何分数,但它将显示为已回答的问题,对其他遇到相同问题的人可能有帮助。 - Jim Garrison
2
是的,我回答了它,但我不能在48小时内接受自己的答案。允许时我会这样做的。谢谢! - roguenet
我在使用JDK6时遇到了同样的问题,与HTTPS服务器端的自签名证书有关。你使用了自签名证书吗? - Oleg Mikheev
我不相信那个服务器有自签名证书,但这是几年前的事了,而且那是一个合作伙伴的服务器,不是我的,所以我记不太清楚了。 - roguenet
显示剩余4条评论
2个回答

65

这是一个 SSL 版本问题。服务器仅支持 SSLv3,而 Java 会从 v2 开始,并尝试向上协商,但并不是所有的服务器都支持这种类型的协商。

强制让 Java 仅使用 SSLv3 是我所知道唯一的解决方案。

编辑,我所知道的有两种方法:

  • 如果您手动创建套接字,可以设置已启用的协议

    socket.setEnabledProtocols(new String[] { "SSLv3" });
    
  • 如果您正在使用一个较高级别的库,您可能需要将所有SSL请求设置为仅使用v3,这可以通过"https.protocols"系统属性来实现:

  • java -Dhttps.protocols=SSLv3
    

11
好的!现在请回答所有剩余的Open SSL问题 :) - President James K. Polk
1
同时,JDK 7 默认使用 TLSv1,而 JDK 8 默认使用 TLSv1.2。来源:https://blogs.oracle.com/java-platform-group/entry/diagnosing_tls_ssl_and_https - Cani
4
可能需要添加所有这些内容来处理其他情况:TLSv1.2、TLSv1.1、TLSv1、SSLv3。 - Agustí Sánchez

0

也许尝试将HTTP版本设置为1.1而不是1.0,因为新标准有一些真正的优势。


1
目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

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