Java HttpsUrlConnection,连接重置
Java HttpsUrlConnection, connection reset
String url1 = "foo1.blabla.com";
String url2 = "foo2_bar.blabla.com";
URLConnection urlConnection = new URL(url1).openConnection();
urlConnection.setDoInput(true);
//Fails
InputStream in = urlConnection.getInputStream();
我们能够毫无问题地连接 url1,但他们最近将 url 更改为 url2,并声称他们只更改了 url 而没有任何更改别的。但是修改后我得到了以下异常:
java.net.SocketException: 连接重置
在 java.net.SocketInputStream.read(SocketInputStream.java:210)
在 java.net.SocketInputStream.read(SocketInputStream.java:141)
在 sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
在 sun.security.ssl.InputRecord.read(InputRecord.java:503)
在 sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:975)
在 sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
在 sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
在 sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
在 sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
我试过了 Java 1.8.181, 1.8.191.
我尝试使用自定义主机名验证程序,例如
class CustomHostNameVerifier 实现 HostnameVerifier {
public CustomHostNameVerifier() {
}
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
}
url1和url2的证书信息相同,我也用keytool把他们的.cer加到keystore里了。
没有防火墙或防病毒问题,因为在同一台计算机上我可以通过邮递员连接到 url2。我在 java 代码中添加了与邮递员相同的 headers。
我检查了以下页面:
What's causing my java.net.SocketException: Connection reset?
java.net.SocketException: Connection reset
- 我运行程序与
-Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager -Djava.security.debug=access:stack
并查看以下差异:
for url1(工作正常)
SendHTTPTest.f9() connection opened Allow unsafe renegotiation: false
Allow legacy hello messages: true Is initial handshake: true Is secure
renegotiation: false main, the previous server name in SNI
(type=host_name (0), value=foo1.blabla.com) was replaced with (type=host_name
(0), value=foo1.blabla.com) Extension extended_master_secret Extension
server_name, server_name: [type=host_name (0), value=foo1.blabla.com]
*** main, WRITE: TLSv1.2 Handshake, length = 226 main, READ: TLSv1.2 Handshake, length = 2303
*** ServerHello, TLSv1.2
for url2(连接重置问题)
SendHTTPTest.f9() connection opened
main, "foo2_bar.blabla.com" is not a legal HostName for server name indication Allow unsafe renegotiation: false Allow legacy hello messages: true Is
initial handshake: true Is secure renegotiation: false
main, "foo2_bar.blabla.com" is not a legal HostName for server name indication
main, WRITE: TLSv1.2 Handshake, length = 193 main, handling exception:
java.net.SocketException: Connection reset main, SEND TLSv1.2 ALERT:
fatal, description = unexpected_message main, WRITE: TLSv1.2 Alert,
length = 2 main, Exception sending alert: java.net.SocketException:
Connection reset by peer: socket write error main, called
closeSocket() java.net.SocketException: Connection reset
可能是消息导致 main, "foo2_bar.blabla.com" is not a legal HostName for server name indication 问题,是否与 SNI 相关? url2 中的下划线可能会导致问题?
SNI client-side mystery using Java8
(来自评论解决,搜索)
很多事情都可能导致 SSL/TLS 握手时重置,具体取决于服务器,但现在常见的是 missing Server Name Indication (SNI) .
除了一些旧版本中的错误,Java (JSSE) 在某些情况下无法发送 SNI:
主机名是一个 IP 地址(v4 或 v6)
主机名不包含点,或末尾有点(即 'look like' 不是 DNS 名称)
主机名包含字母、数字和连字符(在 DNS 和 IDN 允许的位置)和点(在 DNS 允许的位置)以外的 ASCII 字符;此限制显然基于 STD3=RFC1123 中引用的 RFC952。 (NonASCII 字符 -- Unicode U+0080 及以上 -- 按照 IDN 规则转换为 punycode,其设计符合限制。)
本例中的问题是第三点;主机名包含一个 ASCII 下划线。
String url1 = "foo1.blabla.com";
String url2 = "foo2_bar.blabla.com";
URLConnection urlConnection = new URL(url1).openConnection();
urlConnection.setDoInput(true);
//Fails
InputStream in = urlConnection.getInputStream();
我们能够毫无问题地连接 url1,但他们最近将 url 更改为 url2,并声称他们只更改了 url 而没有任何更改别的。但是修改后我得到了以下异常:
java.net.SocketException: 连接重置 在 java.net.SocketInputStream.read(SocketInputStream.java:210) 在 java.net.SocketInputStream.read(SocketInputStream.java:141) 在 sun.security.ssl.InputRecord.readFully(InputRecord.java:465) 在 sun.security.ssl.InputRecord.read(InputRecord.java:503) 在 sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:975) 在 sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367) 在 sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395) 在 sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379) 在 sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
我试过了 Java 1.8.181, 1.8.191.
我尝试使用自定义主机名验证程序,例如
class CustomHostNameVerifier 实现 HostnameVerifier {
public CustomHostNameVerifier() { } @Override public boolean verify(String arg0, SSLSession arg1) { return true; }
}
url1和url2的证书信息相同,我也用keytool把他们的.cer加到keystore里了。
没有防火墙或防病毒问题,因为在同一台计算机上我可以通过邮递员连接到 url2。我在 java 代码中添加了与邮递员相同的 headers。
我检查了以下页面:
What's causing my java.net.SocketException: Connection reset?
java.net.SocketException: Connection reset
- 我运行程序与 -Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager -Djava.security.debug=access:stack
并查看以下差异:
for url1(工作正常)
SendHTTPTest.f9() connection opened Allow unsafe renegotiation: false Allow legacy hello messages: true Is initial handshake: true Is secure renegotiation: false main, the previous server name in SNI (type=host_name (0), value=foo1.blabla.com) was replaced with (type=host_name (0), value=foo1.blabla.com) Extension extended_master_secret Extension server_name, server_name: [type=host_name (0), value=foo1.blabla.com] *** main, WRITE: TLSv1.2 Handshake, length = 226 main, READ: TLSv1.2 Handshake, length = 2303 *** ServerHello, TLSv1.2
for url2(连接重置问题)
SendHTTPTest.f9() connection opened main, "foo2_bar.blabla.com" is not a legal HostName for server name indication Allow unsafe renegotiation: false Allow legacy hello messages: true Is initial handshake: true Is secure renegotiation: false main, "foo2_bar.blabla.com" is not a legal HostName for server name indication main, WRITE: TLSv1.2 Handshake, length = 193 main, handling exception: java.net.SocketException: Connection reset main, SEND TLSv1.2 ALERT: fatal, description = unexpected_message main, WRITE: TLSv1.2 Alert, length = 2 main, Exception sending alert: java.net.SocketException: Connection reset by peer: socket write error main, called closeSocket() java.net.SocketException: Connection reset
可能是消息导致 main, "foo2_bar.blabla.com" is not a legal HostName for server name indication 问题,是否与 SNI 相关? url2 中的下划线可能会导致问题?
SNI client-side mystery using Java8
(来自评论解决,搜索)
很多事情都可能导致 SSL/TLS 握手时重置,具体取决于服务器,但现在常见的是 missing Server Name Indication (SNI) .
除了一些旧版本中的错误,Java (JSSE) 在某些情况下无法发送 SNI:
主机名是一个 IP 地址(v4 或 v6)
主机名不包含点,或末尾有点(即 'look like' 不是 DNS 名称)
主机名包含字母、数字和连字符(在 DNS 和 IDN 允许的位置)和点(在 DNS 允许的位置)以外的 ASCII 字符;此限制显然基于 STD3=RFC1123 中引用的 RFC952。 (NonASCII 字符 -- Unicode U+0080 及以上 -- 按照 IDN 规则转换为 punycode,其设计符合限制。)
本例中的问题是第三点;主机名包含一个 ASCII 下划线。