【问题标题】:Java HttpsUrlConnection, connection resetJava HttpsUrlConnection,连接重置
【发布时间】:2020-09-11 22:46:19
【问题描述】:
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。

  • 我尝试使用自定义主机名验证器,例如

    类 CustomHostNameVerifier 实现 HostnameVerifier {

      public CustomHostNameVerifier() {
    
      }
    
      @Override
      public boolean verify(String arg0, SSLSession arg1) {
    
          return true;
      }
    

    }

  • url1 和 url2 都具有相同的证书信息,我还使用 keytool 将它们的 .cer 添加到密钥库中。

  • 没有防火墙或防病毒问题,因为在同一台计算机上我可以使用邮递员连接到 url2。我在我的 java 代码中添加了与 postman 相同的标头。

  • 我检查了以下页面:

java.net.SocketException: Connection reset With HTTPConnection

What's causing my java.net.SocketException: Connection reset?

java.net.SocketException: Connection reset

connection reset on HttpsUrlConnection with valid URL

  • 我运行程序 -Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager -Djava.security.debug=access:stack

并查看以下差异:

对于 url1(工作正常)

SendHTTPTest.f9() 连接打开 允许不安全的重新协商:false 允许遗留问候消息:true 是初始握手:true 是安全的 renegotiation: false main, SNI 中之前的服务器名称 (type=host_name (0), value=foo1.blabla.com) 被替换为 (type=host_name (0), value=foo1.blabla.com) 扩展 extended_master_secret 扩展 server_name, server_name: [type=host_name (0), value=foo1.blabla.com] *** 主要,写入:TLSv1.2 握手,长度 = 226 主要,读取:TLSv1.2 握手,长度 = 2303 *** 服务器你好,TLSv1.2

对于 url2(连接重置问题)

SendHTTPTest.f9() 连接打开 ma​​in, "foo2_bar.blabla.com" 不是用于服务器名称指示的合法主机名 允许不安全的重新协商:false 允许遗留问候消息:true 是 初始握手:true 是否安全重新协商:false ma​​in, "foo2_bar.blabla.com" 不是用于服务器名称指示的合法主机名 main, WRITE: TLSv1.2 Handshake, length = 193 main, 处理异常: java.net.SocketException:连接重置主,发送 TLSv1.2 警报: 致命的,描述 = 意外消息主要,写:TLSv1.2 警报, length = 2 main, 异常发送警报:java.net.SocketException: 对等方重置连接:套接字写入错误主,调用 closeSocket() java.net.SocketException: 连接重置

可能该消息导致 ma​​in, "foo2_bar.blabla.com" 不是用于服务器名称指示的合法主机名 问题,它与 SNI 相关吗? url2中的下划线可能会导致问题?

SNI client-side mystery using Java8

【问题讨论】:

  • 我从 u2 中删除了域名并替换为 ip 地址,错误消息 foo2 it not a legal HostName for server name indiction 消失了,但问题继续存在 *** main, WRITE: TLSv1.2握手,长度 = 193 主,处理异常:java.net.SocketException:连接重置主,发送 TLSv1.2 警报:致命,描述 = 意外消息主,写入:TLSv1.2 警报,长度 = 2 主,异常发送警报:java .net.SocketException:对等方重置连接:socket 写入错误 main,调用 closeSocket()
  • 当今许多 HTTPS 服务器都需要 SNI,如果您使用(包含)地址或仅单标签名称的 URL,而不是带有至少一个点的 DNS 格式名称,Java/JSSE 可以不发送 SNI,导致握手失败。查看调试日志的all,它显示了这一点。 (如果您的系统上有其他名称解析,例如 /etc/hosts 或 NIS 或 mDNS,则该名称实际上不需要在 DNS 中,它必须是 DNS 格式。)顺便说一句,如果主机名或证书验证是问题,它会产生非常不同的症状,永远不要重置连接,所以那些只会降低你的安全性。
  • Url1 的格式为 blabla.foo1 。 com 和 url2 的格式为 blabla_nteapi.foo2 。 com 下划线会导致问题吗?或者他们在他们的文档中称之为 nte api 是什么,还有一个 tnt api 和一个我以前没有听说过的招摇链接。在旧网址中,我从未听说过它们
  • 确实可以!我没读够。 JSSE 中的代码直接禁止地址和无点(还有点在末尾​​i>,我没有提到但很少使用)。然而,它随后调用java.net.IDN 来处理“国际化”名称(即包含转换为“punycode”的非 ASCII 图形的域名)并且 that 应用禁止除字母之外的所有 ASCII 字符的规则、数字、连字符(不在开头或结尾)和点(受 DNS 限制)。它将这些归因于 STD3=RFC1123,但实际上引用了 RFC952。你可能不走运。对不起:-(
  • benchpresser - 除非您使用 @dave_thompson_085 通知 Dave,否则他不会收到您的评论通知。您无需再通知他,因为他会收到此评论的通知。

标签: java ssl https httpurlconnection connection-reset


【解决方案1】:

(来自 cmets 的解析和搜索)

很多事情都可能导致 SSL/TLS 握手重置,具体取决于服务器,但现在常见的是缺少Server Name Indication (SNI)

除了一些旧版本的错误之外,Java (JSSE) 在某些情况下无法发送 SNI

  • 主机名是 IP 地址(v4 或 v6)

  • 主机名不包含点,或末尾有点(即“看起来不像”DNS 名称)

  • 主机名包含除字母、数字和连字符(在 DNS 和 IDN 允许的位置)和点(在 DNS 允许的位置)之外的 ASCII 字符;此限制显然基于 STD3=RFC1123 中引用的 RFC952。 (NonASCII 字符 -- Unicode U+0080 及以上 -- 按照 IDN 规则转换为 punycode,这在设计上满足了限制。)

在这种情况下,问题在于第三点;主机名包含一个 ASCII 下划线。

【讨论】:

    猜你喜欢
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    • 2013-06-12
    • 2011-01-11
    • 2013-05-29
    • 2013-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多