使用Jetty和JavaScript客户端设置安全WebSocket服务器

使用Jetty和JavaScript客户端设置安全WebSocket服务器,javascript,java,ssl,websocket,Javascript,Java,Ssl,Websocket,我正在尝试使用Jetty设置一个安全的WebSocket服务器,如下所示: import java.util.ArrayList; import java.util.List; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.

我正在尝试使用Jetty设置一个安全的WebSocket服务器,如下所示:

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.websocket.server.WebSocketHandler;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;


public class WebSocketServer
{
    private Server server;
    private String host="localhost";
    private int port=8080;
    private String keyStorePath = "C:\\keystore";
    private String keyStorePassword="password";
    private String keyManagerPassword="password";
    private List<Handler> webSocketHandlerList = new ArrayList();
    MessageHandler messagehandler;

    public WebSocketServer()
    {
        System.out.println("WebSocketServer");

        server = new Server();

        // connector configuration
        SslContextFactory sslContextFactory = new SslContextFactory();
        sslContextFactory.setKeyStorePath(keyStorePath);
        sslContextFactory.setKeyStorePassword(keyStorePassword);
        sslContextFactory.setKeyManagerPassword(keyManagerPassword);
        SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString());
        HttpConnectionFactory httpConnectionFactory = new HttpConnectionFactory(new HttpConfiguration());
        ServerConnector sslConnector = new ServerConnector(server, sslConnectionFactory, httpConnectionFactory);
        sslConnector.setHost(host);
        sslConnector.setPort(port);
        server.addConnector(sslConnector);

        // handler configuration
        HandlerCollection handlerCollection = new HandlerCollection();
        handlerCollection.setHandlers(webSocketHandlerList.toArray(new Handler[0]));
        server.setHandler(handlerCollection);

        WebSocketHandler wsHandler = new WebSocketHandler() {
            @Override
            public void configure(WebSocketServletFactory webSocketServletFactory) {
                webSocketServletFactory.register(MyWebSocketHandler.class);
            }
        };
        ContextHandler wsContextHandler = new ContextHandler();
        wsContextHandler.setHandler(wsHandler);
        wsContextHandler.setContextPath("/");  // this context path doesn't work ftm
        webSocketHandlerList.add(wsHandler);

        messagehandler = new MessageHandler();
        new Thread(messagehandler).start();

        try {
            server.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
之后,我将文件移动到C目录中,以便于使用路径

通过这种配置,我的服务器似乎可以毫无问题地启动。因此,我尝试通过我的网站连接到它,如下所示:

ws = new WebSocket("wss://localhost:8080/");

这根本不起作用。就像我写的一样,我认为我必须配置SSL证书。此外,为了创建我使用的服务器,java客户端实现了一个
truststore
。我必须为JavaScript做类似的事情吗?

回答这个问题可能有点晚了,但经过多次尝试,我已经成功了


首先有几个一般性考虑:

  • 作为要遵循的一般规则(对node.js也有效),您必须首先使HTTPS工作,WSS才能工作。WebSocket通过HTTP工作,因此如果您的服务器正确配置了HTTPS(或HTTP),那么向其中添加WebSocket将使WSS(或WS)工作。实际上,HTTPS/WSS和HTTP/WS可以同时工作

  • 证书非常重要,因为并非所有类型的证书都能与Jetty一起使用(node.js也是如此)。因此,您必须生成Jetty将接受的证书

  • 使HTTPS工作对于自签名证书也很重要,因为您可能必须首先通过HTTPS访问服务器并添加异常,然后WSS才能工作(这可能取决于浏览器)

  • 另一个需要考虑的是上下文路径也需要正确地设置。我为HTTP和WS提供了独立的路径,比如HTTP的
    /hello
    和WS的
    /WS
    。这两种方法可能都使用相同的上下文路径,但我还没有对此进行研究


以下是我遵循的步骤。 我在GitHub上安装了一个

1) 使用中的命令生成正确的自签名证书

上面的链接有一个关于如何生成正确的自签名证书的示例。(如果您有CA签名的证书,我认为过程有些不同。)

我将命令粘贴到这里以便于访问。请注意,无论何时询问,请始终提供相同的密码(包括最后一个步骤,当您键入的密码将以明文显示在屏幕上时)

openssl genrsa-aes256-out jetty.key
openssl req-new-x509-key jetty.key-out jetty.crt
keytool-keystore-keystore-import-alias jetty-file jetty.crt-trustcacerts
openssl请求-新建-密钥jetty.key-out jetty.csr
openssl pkcs12-inkey jetty.key-in jetty.crt-export-out jetty.pkcs12
keytool-importkeystore-srckeystore jetty.pkcs12-srcstoretypkcs12-destkeystore密钥库
2) 在Jetty中具有正确的HTTPS代码

网络上有一些资源展示了如何使用Jetty实现HTTPS,但对我来说,只有一个有用,就是它

3) 使用正确的代码来处理上下文

这是一个很难的例子-从Jetty文档页面的代码不适合我。 成功的是。本教程还告诉我,如果我尝试对HTTP和WS使用相同的路径,可能会发生冲突

4) 最后,为WebSocket编写正确的代码


我找到了正确的WebSocket代码。我们需要的是
本地jetty websocket示例

我想补充riverhorse的答案(我想添加一条评论,但在撰写本文时,我没有对答案发表评论所需的50个声誉)

虽然这个答案说明了如何使用自签名密钥完成此过程,但我知道了如何使用CA签名的证书

要做到这一点,我将假设你有权访问3个文件,这是你通常收到的文件 购买CA签名的证书时

注意:您可能有example.crt、example_key.txt等文件 各种各样的变化。只要有内容,那就无所谓了 匹配他们要描述的文件。换句话说,所有的 文件只是文本,所以只要它们包含 然后您可以使用该文件(或者您可以更改 姓名)

第一步是将主证书和中间证书合并到一个文件中,如下所示

请注意,顺序很重要,主证书应在中间证书之前

现在,下一步是使用example.key和新的cert-chain.txt生成pkcs12文件(然后可以将其放入密钥库)。这些步骤与riverhorse的答案非常相似

快跑

每次它要求输入密码时,请保持不变,您最终将在代码中使用它

最后一步是使用

keytool -importkeystore -srckeystore example.pkcs12 -srcstoretype PKCS12 -destkeystore keystore
如果遇到类似
无法加载证书140126084731328:错误:0908F066:PEM例程:获取_头_和_数据:错误结束行:../crypto/PEM/PEM_lib.c:842
请检查此答案的底部是否有对我有效的潜在修复方法

现在,您有了jetty程序的密钥库,您可以返回riverhorse的示例,了解如何应用该密钥库

如果要检查密钥库是否具有可以运行的证书

keytool -list -v -keystore keystore > output_filename.txt
然后使用
cat output_filename.txt
nano output_filename.txt
查看内容

这些步骤来自riverhorse的答案以及下面的2个链接

在显示整体步骤方面确实很有帮助,但我直到将其与其他链接结合后才发现成功(但是您的里程数可能会有所不同,因为我很可能在第一次尝试时出错)

检查标题“通过PKCS12加载密钥和证书”,该链接通常有些过时,因为此时使用openssl命令将PKCS12加载到密钥库不是一件事,但它展示了如何最好地处理中间证书

势F
cat example.cer example.ca-bundle > cert-chain.txt
openssl pkcs12 -export -inkey example.key -in cert-chain.txt -out example.pkcs12
keytool -importkeystore -srckeystore example.pkcs12 -srcstoretype PKCS12 -destkeystore keystore
keytool -list -v -keystore keystore > output_filename.txt
-----END CERTIFICATE----------BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----