【问题标题】:Jetty ssl port not open for secure JSR-356 websocketsJetty ssl 端口未为安全的 JSR-356 websockets 打开
【发布时间】:2015-04-23 16:24:38
【问题描述】:

我正在编写一个使用嵌入式 Jetty 9.3.0.M2 的安全 websocket 的服务器应用程序。当我在没有安全套接字的情况下运行它时,一切都好办,但是当我启用安全套接字时,我的客户端被拒绝连接,并且 nmap 显示端口已关闭。服务器端的日志中没有错误。

我相信我的 .jks、.crt、.pem 和 .key 文件以及我的密钥库密码都是正确的,因为同一服务器上的其他应用程序正在使用相同的文件并且正在运行。

这是启动 Jetty 服务器的代码。使用常规套接字时一切正常。

if (keyStorePath != null) {
    // use secure sockets
    server = new Server();
    HttpConfiguration https = new HttpConfiguration();
    https.addCustomizer(new SecureRequestCustomizer());

    SslContextFactory sslContextFactory = new SslContextFactory();
    sslContextFactory.setKeyStorePath(keyStorePath);
    sslContextFactory.setKeyStorePassword(keyStorePassword);
    sslContextFactory.setKeyManagerPassword(keyStorePassword);
    ServerConnector sslConnector = new ServerConnector(server, 
            new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), 
            new HttpConnectionFactory(https));
    sslConnector.setHost(serverName); // EDIT: this line was the problem, removing it fixed everything.
    sslConnector.setPort(port);
    server.setConnectors(new Connector[] { sslConnector });
} else {
    // use regular sockets
    server = new Server(port);
}

server.setStopAtShutdown(true);
server.setDumpAfterStart(false);
server.setDumpBeforeStop(false);

// Initialize JSR-356 style websocket
ServletContextHandler servletContextHandler = 
        new ServletContextHandler(ServletContextHandler.SESSIONS);
servletContextHandler.setContextPath(contextPath);
server.setHandler(servletContextHandler);
ServerContainer container = 
        WebSocketServerContainerInitializer.configureContext(servletContextHandler);
container.addEndpoint(MyWebsocketEndpoint.class);
server.start();
logger.info("Started server: " + server);
if (server.getConnectors().length > 0) {
    logger.info("Connector = " + server.getConnectors()[0] + 
            " isRunning=" + server.getConnectors()[0].isRunning());
}

当 keyStorePath 不为空(即使用安全套接字)时,日志如下所示:

2015-04-23 16:07:37.634:INFO::main: Logging initialized @114ms
2015-04-23 16:07:37.863:INFO:oejs.Server:main: jetty-9.3.0.M2
2015-04-23 16:07:38.408:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@3abd7ff4{/websockets,null,AVAILABLE}
2015-04-23 16:07:38.489:INFO:oejs.ServerConnector:main: Started ServerConnector@2e4996ea{SSL,[ssl, http/1.1]}{my.server.com:8085}
2015-04-23 16:07:38.490:INFO:oejs.Server:main: Started @973ms
Apr 23, 2015 4:07:38 PM com.crowdoptic.conference.jetty.JettyWebSocketServer start
INFO: Started server: org.eclipse.jetty.server.Server@7205c140
Apr 23, 2015 4:07:38 PM com.crowdoptic.conference.jetty.JettyWebSocketServer start
INFO: Connector = ServerConnector@2e4996ea{SSL,[ssl, http/1.1]}{my.server.com:8085} isRunning=true

nmap 在 8085 端口显示

PORT     STATE  SERVICE
8085/tcp closed unknown

我的 JavaScript 控制台中的错误是“连接建立错误:net::ERR_CONNECTION_REFUSED”

当 keyStorePath 为 null(表示使用套接字)时,日志如下所示:

2015-04-23 16:15:19.624:INFO::main: Logging initialized @115ms
2015-04-23 16:15:19.847:INFO:oejs.Server:main: jetty-9.3.0.M2
2015-04-23 16:15:20.431:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@403108f6{/websockets,null,AVAILABLE}
2015-04-23 16:15:20.446:INFO:oejs.ServerConnector:main: Started ServerConnector@4efce9a2{HTTP/1.1,[http/1.1]}{0.0.0.0:8085}
2015-04-23 16:15:20.450:INFO:oejs.Server:main: Started @941ms
Apr 23, 2015 4:15:20 PM com.crowdoptic.conference.jetty.JettyWebSocketServer start
INFO: Started server: org.eclipse.jetty.server.Server@57a20888
Apr 23, 2015 4:15:20 PM com.crowdoptic.conference.jetty.JettyWebSocketServer start
INFO: Connector = ServerConnector@4efce9a2{HTTP/1.1,[http/1.1]}{0.0.0.0:8085} isRunning=true

nmap 在 8085 端口显示

PORT     STATE  SERVICE
8085/tcp open   unknown

该应用在浏览器中运行良好。我难住了。我尝试了许多代码排列来设置 SSL,但无济于事。感谢您查看此内容。

已编辑以明确说明我使用的是 JSR-356 websockets 而不是 Jetty 原生 websockets。

已编辑将解决方案放入示例代码的 cmets 中。

【问题讨论】:

    标签: ssl websocket jetty embedded-jetty


    【解决方案1】:

    Jetty 9.3.0 仍在进行更改且不稳定。

    首先,让我们使用 Jetty 的稳定版本,即 9.2.10.v20150310。

    您在示例中设置的 SSL、SslContextFactory 和 ServerConnector 是正确的。

    示例(使用在jetty-distribution/demo-base/etc 中找到的预先创建的keystore 文件):

    package jetty.websocket;
    
    import java.io.FileNotFoundException;
    import java.net.URL;
    
    import javax.websocket.OnMessage;
    import javax.websocket.server.ServerContainer;
    import javax.websocket.server.ServerEndpoint;
    
    import org.eclipse.jetty.server.HttpConfiguration;
    import org.eclipse.jetty.server.HttpConnectionFactory;
    import org.eclipse.jetty.server.SecureRequestCustomizer;
    import org.eclipse.jetty.server.Server;
    import org.eclipse.jetty.server.ServerConnector;
    import org.eclipse.jetty.server.SslConnectionFactory;
    import org.eclipse.jetty.server.handler.DefaultHandler;
    import org.eclipse.jetty.server.handler.HandlerList;
    import org.eclipse.jetty.servlet.ServletContextHandler;
    import org.eclipse.jetty.util.ssl.SslContextFactory;
    import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
    
    public class SecureJavaxWebSocketServer
    {
        @ServerEndpoint(value="/echo")
        public static class EchoSocket
        {
            @OnMessage
            public String onMessage(String msg)
            {
                return msg;
            }
        }
    
        public static void main(String[] args)
        {
            try
            {
                new SecureJavaxWebSocketServer().go();
            }
            catch (Throwable t)
            {
                t.printStackTrace(System.err);
            }
        }
    
        private URL findResource(String path) throws FileNotFoundException
        {
            URL url = Thread.currentThread().getContextClassLoader().getResource(path);
            if (url == null)
            {
                throw new FileNotFoundException("Resource Not Found: " + path);
            }
            return url;
        }
    
        public void go() throws Exception
        {
            Server server = new Server();
            int httpsPort = 9443;
    
            // Setup SSL
            URL keystore = findResource("ssl/keystore");
    
            SslContextFactory sslContextFactory = new SslContextFactory();
            sslContextFactory.setKeyStorePath(keystore.toExternalForm());
            sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
            sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
            sslContextFactory.addExcludeProtocols("SSLv3"); // a good thing to do
            sslContextFactory.addExcludeCipherSuites(".*_GCM_.*"); // geez these ciphers are slow
    
            // Setup HTTPS Configuration
            HttpConfiguration httpsConf = new HttpConfiguration();
            httpsConf.setSecurePort(httpsPort);
            httpsConf.setSecureScheme("https");
            httpsConf.addCustomizer(new SecureRequestCustomizer());
    
            ServerConnector htttpsConnector = new ServerConnector(server,
                    new SslConnectionFactory(sslContextFactory,"http/1.1"),
                    new HttpConnectionFactory(httpsConf));
            htttpsConnector.setPort(httpsPort);
    
            server.addConnector(htttpsConnector);
    
            // Establish base handler list
            HandlerList baseHandlers = new HandlerList();
            server.setHandler(baseHandlers);
    
            // Add Servlet Context
            ServletContextHandler context = new ServletContextHandler();
            context.setContextPath("/");
            baseHandlers.addHandler(context);
    
            // Add WebSocket
            ServerContainer jsrContainer = WebSocketServerContainerInitializer.configureContext(context);
            jsrContainer.addEndpoint(EchoSocket.class);
    
            // Add default handler (for errors and whatnot) - always last
            baseHandlers.addHandler(new DefaultHandler());
    
            // Lets see how the server is setup after it is started
            // server.setDumpAfterStart(true);
    
            try
            {
                // Start the server thread
                server.start();
                // Wait for the server thread to end
                server.join();
            }
            catch (Throwable t)
            {
                t.printStackTrace(System.err);
            }
        }
    }
    

    启动控制台结果:

    2015-04-23 09:53:17.279:INFO::main: Logging initialized @139ms
    2015-04-23 09:53:17.346:INFO:oejs.Server:main: jetty-9.2.10.v20150310
    2015-04-23 09:53:17.370:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@2437c6dc{/,null,AVAILABLE}
    2015-04-23 09:53:17.574:INFO:oejs.ServerConnector:main: Started ServerConnector@71423665{SSL-http/1.1}{0.0.0.0:9443}
    2015-04-23 09:53:17.575:INFO:oejs.Server:main: Started @437ms
    

    环境测试:

    $ netstat -tlnp | grep LISTEN | grep 9443
    (Not all processes could be identified, non-owned process info
     will not be shown, you would have to be root to see it all.)
    tcp6       0      0 :::9443                 :::*                    LISTEN      8918/java 
    
    $ ps auwwwx | grep 8918
    joakim    8918  0.7  0.1 11822896 59728 ?      Sl   09:53   0:00 /home/joakim/java/jvm/jdk-8u31-x64/bin/java -Dfile.encoding=UTF-8 -classpath /home/joakim/code/(..snip..) jetty.websocket.SecureWebSocketServer
    

    您可以使用 echo 测试客户端来测试这个 echo 类

    http://www.websocket.org/echo.html

    只需将表单中的 URL 指向 wss://localhost:9443/echo 并勾选 TLS 复选框。

    【讨论】:

    • 该示例适用于我的环境,即使我将其更改为使用自己的密钥库,所以我知道密钥库不是问题。我将您的 ssl 设置代码完全复制到我的代码中,但是当我尝试运行它时,我仍然收到连接被拒绝,并且 nmap 显示端口已关闭。示例和我的代码之间的唯一区别是我使用的是 JSR-356 websockets 而不是本机 Jetty websockets。 Jetty 是否支持通过 SSL 运行 JSR-356 websockets,还是我需要使用本机 Jetty websockets?
    • 连接器问题与原生 websocket 与 jsr websocket 无关。是的,安全(ssl 和 wss:// 方案)JSR356 websockets 也可以工作。
    • 您是否在代码中设置了httpsConf.setSecurePort(httpsPort);httpsConf.setSecureScheme("https"); 部分?
    • 感谢您的帮助!整个问题出现在第 14 行,我在其中调用了 sslConnector.setHost(serverName)。删除该行解决了问题。
    • sslConnector.setHost(serverName) 适用于您希望连接器绑定到特定主机 IP 网络接口的情况,默认情况下它将使用绑定到所有网络接口的 0.0.0.0 虚拟地址。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-18
    • 2015-05-26
    • 2015-02-14
    • 1970-01-01
    • 2014-11-04
    • 2017-07-20
    相关资源
    最近更新 更多