Java SSL连接重置

Java SSL连接重置,java,php,apache,ssl,openssl,Java,Php,Apache,Ssl,Openssl,我正在尝试连接到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.

我正在尝试连接到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 libs和一个新的URL(“https://...))
  • 正在连接新的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)

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

强迫java只使用SSLv3是我知道的唯一解决方案

编辑,我知道有两种方法可以做到这一点:

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

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

    java -Dhttps.protocols=SSLv3
    

该异常跟踪不会显示代码中出现问题的位置。可能SSL连接已成功建立,问题出在您的HTTP中。在我的代码中出现的位置因我使用的方法而异。它总是发生在out.flush()或开始读取连接时。不过,我包含的部分始终是一样的——问题在于某个时刻的握手。更新:这可能是SSL版本的问题。我发现服务器只支持SSLv3,Java将从v2开始,并尝试向上协商,但并非所有服务器都支持这种协商。当我知道这确实是个问题时,我会再发一次。@Nathan:你应该用答案回答你自己的问题,然后接受你的答案。你不会得到任何分数,但它会以回答问题的形式出现在其他有同样问题的人面前,并且可能会帮助其他人。是的,我回答了,但我不能在48小时内接受我自己的答案。如果允许,我会这样做。谢谢干得好现在回答所有剩余的开放式SSL问题:)JDK 7默认为TLSv1,JDK 8默认为TLSv1.2。来源:您可能需要添加所有这些来处理其他情况:TLSv1.2、TLSv1.1、TLSv1、SSLv3