Java HttpsUrlConnection,连接重置

Java HttpsUrlConnection,连接重置,java,ssl,https,httpurlconnection,connection-reset,Java,Ssl,Https,Httpurlconnection,Connection Reset,我们能够毫无问题地连接url1,但他们最近将url更改为url2,并声称他们只更改了url,其他什么都没有更改。但在修改后,我得到了以下例外: java.net.SocketException:连接重置 位于java.net.SocketInputStream.read(SocketInputStream.java:210) 位于java.net.SocketInputStream.read(SocketInputStream.java:141) 位于sun.security.ssl.Input

我们能够毫无问题地连接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.readfull(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)

  • 我试过Java1.8.181,1.8.191

  • 我尝试使用customhostnameverifier,例如

    类CustomHostNameVerifier实现HostnameVerifier{

    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和url2都有相同的证书信息,我还使用keytool将它们的.cer添加到密钥库中

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

  • 我查看了以下页面:

  • 我用计算机运行程序 -Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager-Djava.security.debug=access:stack
并看到以下区别:

适用于url1(工作正常)

SendHTTPTest.f9()连接已打开允许不安全的重新协商:false 允许旧的hello消息:true是初始握手:true是安全的 重新协商:false main,SNI中以前的服务器名称 (type=host_name(0),value=foo1.blabla.com)被替换为(type=host_name) (0),value=foo1.blabla.com)扩展\u master\u secret扩展 服务器名称,服务器名称:[type=host\u name(0),value=foo1.blabla.com] ***main,写入:TLSv1.2握手,长度=226 main,读取:TLSv1.2握手,长度=2303 ***服务器你好,TLSv1.2

用于url2(连接重置问题)

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

可能该消息导致main,“foo2_bar.blabla.com”不是服务器名称指示的合法主机名该问题与SNI有关吗?url2中的下划线可能会导致问题

(来自用于解决和搜索的注释)

根据服务器的不同,许多情况都会导致SSL/TLS握手重置,但现在常见的情况是丢失

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

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

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

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


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

我从u2中删除了域名并替换为ip地址,错误消息foo2 it not a legal hostname for server name indication消失,但问题仍然存在***main,WRITE:TLSv1.2 Handshake,length=193 main,处理异常:java.net.SocketException:Connection reset main,SEND TLSv1.2 ALERT:fatal,description=unexpected_message main,WRITE:TLSv1.2 ALERT,length=2 main,异常发送ALERT:java.net.SocketException:Connection reset by peer:socket WRITE error main,称为closeSocket()当今许多HTTPS服务器需要SNI,如果使用(包含)地址或仅包含一个标签名的URL,不是至少有一个点的DNS格式名称,Java/JSSE不发送SNI,这会导致握手失败。查看所有调试日志,它显示了这一点。(如果您的系统上有其他名称解析,如/etc/hosts或NIS或MDN,则名称实际上不必在DNS中,它必须是DNS格式。)顺便说一句,如果主机名或证书验证出现问题,它将产生非常不同的症状,决不重置连接,所以这些只是免费降低了您的安全性。Url1的格式是blabla.foo1。com和url2的格式为blabla_nteapi.foo2。com下划线会导致问题吗?或者他们在文档中称之为nte api是什么,还有一个tnt api和一个我以前从未听说过的招摇过市链接。在旧的网址我从来没有听说过他们确实可以!我读得不够远。JSSE中的代码直接禁止地址和无点(最后还有点,我没有提到,但很少使用)。然而,它随后调用
java.net.IDN
来处理“国际化”名称(即包含非ASCII gr的域名)
  public CustomHostNameVerifier() {

  }

  @Override
  public boolean verify(String arg0, SSLSession arg1) {

      return true;
  }