SSL 连接重置
我正在尝试连接到 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 库和新 URL("https://...")
- 连接新 URL("https: //...").openConnection()
手动创建 SSL 连接:
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()); SSLSocketFactory 工厂 = (SSLSocketFactory) SSLSocketFactory.getDefault(); SSLSocket套接字=(SSLSocket)factory.createSocket(“...”,443); Writer out = new OutputStreamWriter(socket.getOutputStream()); // https 需要 GET 行中的完整 URL // out.write("GET / HTTP/1.0\r\n"); out.write("\r\n"); 出.flush(); // 读取响应 BufferedReader = new BufferedReader( 新的InputStreamReader(socket.getInputStream())); 整数c; while ((c = in.read()) != -1) { System.out.write(c); } 关闭(); 附寄(); 套接字.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)
I am attempting to connect to an HTTPS endpoint in Java. Every method I have tried (more details below) ends up generating this stack trace:
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)
I have tried:
- Connecting with the javax SOAP libs and a new URL("https://...")
- Connecting with new URL("https://...").openConnection()
Creating an SSL connection by hand:
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();
A few more details:
- Every method I have tried has worked against other SSL servers, it's this particular server (I am not at liberty to discuss what server, it's a business partner)
- I can connect to this server both with a web browser, and with a faked up SOAP request with curl; This is something Java-specific.
So, it seems pretty clear that there is some disagreement between Java and the HTTPS server over how the handshake should go down, which probably means the server has some strange SSL configuration. However, I don't have direct access to the server, and the people who do are halfway around the world, so communication is a little strained due to very different timezones.
If my assumptions there are correct, what possible SSL problems could there be? What might cause something like this? Where can I ask the people in control of the server to look for issues? When I do the request with curl, I get back these server configuration headers:
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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是SSL版本问题。服务器仅支持 SSLv3,Java 将从 v2 开始,并尝试向上协商,但并非所有服务器都支持该类型的协商。
强制 java 仅使用 SSLv3 是我所知道的唯一解决方案。
编辑,我知道有两种方法可以做到这一点:
如果您手动创建套接字,则可以设置启用的协议
如果您使用更高级别的库,您可能需要将所有 SSL 请求设置为仅使用 v3,即使用
“https.protocols”
系统属性完成:It is an SSL version problem. The server only supports SSLv3, and Java will start at v2, and attempt to negotiate upwards, but not all servers support that type of negotiation.
Forcing java to use SSLv3 only is the only solution I'm aware of.
Edit, there are two ways to do this that I'm aware of:
If you are creating the socket by hand, you can set the enabled protocols
If you are using a higher level library, you probably need to set all SSL requests to use v3 only, which is accomplished with the
"https.protocols"
system property:也许还可以尝试将 HTTP 版本设置为 1.1 而不是 1.0,因为新标准有一些真正的优势。
Maybe also try setting the HTTP version to 1.1 instead of 1.0, as there's some real advantages to the newer standard.