【问题标题】:TLS extension "Server Name Indication" (SNI): value not available on server sideTLS 扩展“服务器名称指示”(SNI):值在服务器端不可用
【发布时间】:2014-01-20 04:04:38
【问题描述】:

基于 JSSE 示例,我试图在服务器端获取 TLS 参数“服务器名称指示”(SNI) 的值 - 但没有成功。我确定该值是由客户端发送的,因为我使用了显示该值的网络嗅探器(Wireshark)。

但是当我使用以下代码片段时,服务器名称参数列表为空(同时显示“协议”):

public void connectionAccepted(Socket socket) 
{ 
  System.out.println("Connection accepted!"); 
  try { 
    /* get SNI parameter */ 
    SSLSocket sslSocket = (SSLSocket)socket; 
    SSLParameters sslParams = sslSocket.getSSLParameters(); 

    List<SNIServerName> serverNames = sslParams.getServerNames(); 
    for(SNIServerName item : serverNames){ 
      System.out.println("SNI: " + item.toString()); 
    } 

    String[] protocols = sslParams.getProtocols(); 
    for(String item : protocols) { 
      System.out.println("Protocols: " + item.toString()); 
    } 
  } catch (Exception e) { 
    e.printStackTrace(); 
  } 
} 

【问题讨论】:

    标签: java ssl java-8 sni


    【解决方案1】:

    无论出于何种原因,Java SNI 实现显然没有在服务器端提供实际的主机名。相反,文档 [1](在“基于 SSLSocket 的虚拟服务器调度程序”下)建议手动解析初始 SSL 数据包并从中提取服务器名称。

    您还可以使用 SNIMatcher [2] 来要求客户端提供特定名称;如果匹配器不匹配,则客户端在 SSL 层收到错误。

    [1]http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#SNIExamples [2]http://docs.oracle.com/javase/8/docs/api/javax/net/ssl/SNIMatcher.html

    更新:我编写了一个自定义 SNI 解析器,它的工作原理如下:客户端将 SNI 作为 SSL ClientHello 消息的一部分发送,这是作为设置的一部分发送的第一条消息SSL 连接。我的实现首先对其进行解析,然后使用与请求的主机名匹配的正确服务器端证书设置 SSLEngine。

    【讨论】:

    • 非常感谢。我尝试了您提出的解决方案“1”,它成功了。
    【解决方案2】:

    该功能(非常莫名其妙)不能通过 SSLSocket 开箱即用(也不能通过较新的 SSLEngine)。

    我自己也遇到了同样的问题,最后写了一个开源库:TLS Channel。该库的范围实际上更大:它是 SSLEngine 的完整抽象(很难直接使用),将其公开为 ByteChannel。

    关于 SNI,库在创建 SSLEngine 之前解析第一个字节。然后用户可以向服务器通道提供一个函数,根据接收到的域名选择 SSLContexts。

    【讨论】:

      【解决方案3】:

      我会尝试实现我自己的 SNIMatcher(扩展抽象的)并在他们访问 mymatcher.matches(...) 方法时拦截并保存 sniservername(另一个抽象)。

      如果sniservername instanceof snihostname,则snihostname.getAsciiName()。否则,您将不得不研究如何读取 sniservername.getEncoded() byte[]。

      一旦退出握手和连接,我会检查我的 snimatcher 上保留的主机名。当你手头有 sniservername 对象时,你可能必须取出字符串主机名,因为,谁知道(你会的!),它可能在 snimatcher.matches(...) 调用后立即变得无效。

      【讨论】:

        猜你喜欢
        • 2013-07-23
        • 2017-05-23
        • 1970-01-01
        • 2012-09-03
        • 1970-01-01
        • 2011-07-04
        • 1970-01-01
        • 2011-12-19
        相关资源
        最近更新 更多