简体   繁体   English

在java中使用自签名证书连接到websocket

[英]Connect to websocket with self-signed certificate in java

I need to use Java to connect to a WebSocket server that is using a self-signed certificate.我需要使用 Java 连接到使用自签名证书的 WebSocket 服务器。 I'm trying to use the Jetty library and am pretty new at Java but I am finding it very difficult to figure out what needs to be done.我正在尝试使用 Jetty 库,并且在 Java 方面还是很新的,但我发现很难弄清楚需要做什么。 I can connect using NodeJS very simply:我可以非常简单地使用 NodeJS 进行连接:

const WebSocket = require('ws');
const ws = new WebSocket('wss://192.168.100.220:9000/', ['ws-valence'], {
  rejectUnauthorized: false,
});

However, modifying the example I found on the Jetty docs doesn't get me very far.但是,修改我在Jetty 文档上找到的示例并没有让我走得很远。

I implemented a basic client that works well with an echo test server, like in the example linked above.我实现了一个与回声测试服务器配合良好的基本客户端,就像上面链接的例子一样。 Then I went on to configure it with my own protocol and IP Address:然后我继续用我自己的协议和 IP 地址配置它:

  private static void connectToBasestation() {

//    String destUri = "ws://echo.websocket.org";
    String basestationUri = "wss://192.168.100.220:9000/";
    SslContextFactory ssl = new SslContextFactory(); // ssl config
    ssl.setTrustAll(true); // trust all certificates
    WebSocketClient client = new WebSocketClient(ssl); // give ssl config to client
    BasestationSocket socket = new BasestationSocket();
    ArrayList<String> protocols = new ArrayList<String>();
    protocols.add("ws-valence");

    try
    {
        client.start();
        URI bsUri = new URI(basestationUri);
        ClientUpgradeRequest request = new ClientUpgradeRequest();
        request.setSubProtocols(protocols);
        client.connect(socket, bsUri, request);
        System.out.printf("Connecting to : %s%n", bsUri);

        // wait for closed socket connection.
        socket.awaitClose(5,TimeUnit.SECONDS);
    }
    catch (Throwable t)
    {
        t.printStackTrace();
    }
    finally
    {
        try
        {
            client.stop();
        }
        catch (Exception e)
        {
            e.printStackTrace();

        }
    }
  }

However, I'm getting an UpgradeException with 0 null as the values and my onConnect method is never getting called.但是,我收到了一个UpgradeException 0 nullUpgradeException ,并且我的onConnect方法永远不会被调用。 I'm guessing this is a security issue, but I can't be certain since the server is an old machine -- a bit of a black box.我猜这是一个安全问题,但我不能确定,因为服务器是一台旧机器——有点像黑匣子。 But I'm thinking maybe something is wrong with my approach?但我在想也许我的方法有问题? Can anyone lend any advice here?任何人都可以在这里提供任何建议吗?

Edit 1: Included trustful SSL factory as suggested.编辑 1:按照建议包含可信任的 SSL 工厂。 It did not change anything, including the stack trace from below.它没有改变任何东西,包括下面的堆栈跟踪。

Edit 3: There is a similar question listed above, but this is different since 1) I'm getting a different error code and 2) Adding a trustful SSL factory does not solve the issue.编辑 3:上面列出了一个类似的问题,但这是不同的,因为 1) 我收到了不同的错误代码 2) 添加可信任的 SSL 工厂并不能解决问题。

Edit 2: Here is the stack trace I am getting from my OnError below:编辑 2:这是我从下面的 OnError 中获得的堆栈跟踪:

Caused by: javax.net.ssl.SSLException: Received fatal alert: handshake_failure
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
    at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1666)
    at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1634)
    at sun.security.ssl.SSLEngineImpl.recvAlert(SSLEngineImpl.java:1800)
    at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:1083)
    at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:907)
    at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:781)
    at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
    at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.fill(SslConnection.java:681)
    at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.process(HttpReceiverOverHTTP.java:128)
    at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:73)
    at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:133)
    at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:155)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:281)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)
    at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:291)
    at org.eclipse.jetty.io.ssl.SslConnection$3.succeeded(SslConnection.java:151)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)
    at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
    ... 3 more
org.eclipse.jetty.websocket.api.UpgradeException: 0 null
    at org.eclipse.jetty.websocket.client.WebSocketUpgradeRequest.onComplete(WebSocketUpgradeRequest.java:522)
    at org.eclipse.jetty.client.ResponseNotifier.notifyComplete(ResponseNotifier.java:216)
    at org.eclipse.jetty.client.ResponseNotifier.notifyComplete(ResponseNotifier.java:208)
    at org.eclipse.jetty.client.HttpReceiver.terminateResponse(HttpReceiver.java:470)
    at org.eclipse.jetty.client.HttpReceiver.abort(HttpReceiver.java:552)
    at org.eclipse.jetty.client.HttpChannel.abortResponse(HttpChannel.java:156)
    at org.eclipse.jetty.client.HttpSender.terminateRequest(HttpSender.java:381)
    at org.eclipse.jetty.client.HttpSender.abort(HttpSender.java:566)
    at org.eclipse.jetty.client.HttpSender.anyToFailure(HttpSender.java:350)
    at org.eclipse.jetty.client.HttpSender$CommitCallback.failed(HttpSender.java:717)
    at org.eclipse.jetty.client.http.HttpSenderOverHTTP$HeadersCallback.failed(HttpSenderOverHTTP.java:310)
    at org.eclipse.jetty.io.WriteFlusher$PendingState.fail(WriteFlusher.java:263)
    at org.eclipse.jetty.io.WriteFlusher.onFail(WriteFlusher.java:516)
    at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint$FailWrite.run(SslConnection.java:1251)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:762)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:680)
    at java.lang.Thread.run(Thread.java:748)

A TLS/SSL handshake error is rather generic. TLS/SSL 握手错误相当普遍。

You don't know what part of the TLS/SSL handshake the issue occurred in.您不知道问题发生在 TLS/SSL 握手的哪个部分。

You can use -Djavax.net.debug=all command line option on Java to see the raw details of the TLS/SSL handshake, and this might be a good place to start troubleshooting your issues with.您可以在 Java 上使用-Djavax.net.debug=all命令行选项来查看 TLS/SSL 握手的原始详细信息,这可能是开始解决问题的好地方。

Some options ...一些选择...


For certificate name issues对于证书名称问题

If you connect to a server and the provided certificate does not match the hostname you used in the URI to connect, this is a violation of the endpoint identification algorithm present in Java itself.如果您连接到服务器并且提供的证书与您在 URI 中用于连接的主机名不匹配,则这违反了 Java 本身中存在的端点识别算法。

Example Scenario:示例场景:

  1. You connect to wss://192.168.1.0:8443/chat您连接到wss://192.168.1.0:8443/chat
  2. The certificate reports itself as chatserver.acme.com证书将自身报告为chatserver.acme.com

This is a violation, as the hostname in the URI 192.168.1.0 does not match the certificate chatserver.acme.com这是违规行为,因为 URI 192.168.1.0中的主机名与证书chatserver.acme.com不匹配

This is especially common when testing with wss://localhost or wss://127.0.0.1这在使用wss://localhostwss://127.0.0.1测试时尤其常见

You can tell Java to not perform the Endpoint Identification check like this ...你可以告诉 Java 不要像这样执行端点识别检查......

SslContextFactory.Client ssl = new SslContextFactory.Client(); // ssl config
ssl.setEndpointIdentificationAlgorithm(null); // disable endpoint identification algorithm.
WebSocketClient client = new WebSocketClient(ssl); // give ssl config to client

⚠️ WARNING: This is not recommended, and can easily allow for man-in-the-middle attacks! ⚠️警告:不推荐这样做,很容易被中间人攻击!


For a certificate trust issues对于证书信任问题

Try enabling trust for all certificates.尝试为所有证书启用信任。

  1. Enable SSL/TLS for WebSocket Client为 WebSocket 客户端启用 SSL/TLS
  2. Trust All Certificates on the SSL/TLS Configuration信任 SSL/TLS 配置上的所有证书

Example (assuming Jetty 9.4.19.v20190610 or newer):示例(假设 Jetty 9.4.19.v20190610 或更新版本):

SslContextFactory.Client ssl = new SslContextFactory.Client(); // ssl config
ssl.setTrustAll(true); // trust all certificates
WebSocketClient client = new WebSocketClient(ssl); // give ssl config to client

⚠️ WARNING: This is not recommended, and can easily allow for man-in-the-middle attacks! ⚠️警告:不推荐这样做,很容易被中间人攻击!


For certificate algorithm issues对于证书算法问题

The algorithm used to create the certificate will limit the available Cipher Suites made available during the TLS/SSL handshake.用于创建证书的算法将限制在 TLS/SSL 握手期间可用的可用密码套件。

For example, If the server only had a DSA certificate (known vulnerable), then none of the RSA or ECDSA certificates would be available.例如,如果服务器只有一个 DSA 证书(已知易受攻击的证书),那么 RSA 或 ECDSA 证书都不可用。

The number of bits used to create the certificate is also relevant, as if the server certificate had too few, then Java itself will reject it.用于创建证书的位数也是相关的,好像服务器证书太少了,那么 Java 本身就会拒绝它。

If you are in control of the server certificate, make sure you have generated a certificate that contains both a RSA and ECDSA certificate, with at least 2048 bits for RSA (or more), and 256 bits for ECDSA.如果您控制服务器证书,请确保您已生成包含 RSA 和 ECDSA 证书的证书,其中至少 2048 位用于 RSA(或更多),256 位用于 ECDSA。


For a cipher suite issues对于密码套件问题

Try an empty Cipher Suite exclusion list on the Jetty side.在 Jetty 端尝试一个空的密码套件排除列表。

⚠️ WARNING: This lets you use KNOWN vulnerable Cipher Suites! ⚠️ 警告:这让您可以使用已知的易受攻击的密码套件!

  1. Enable SSL/TLS for WebSocket Client为 WebSocket 客户端启用 SSL/TLS
  2. Blank out the Cipher Suite Exclusion List清除密码套件排除列表

Example (assuming Jetty 9.4.19.v20190610 or newer):示例(假设 Jetty 9.4.19.v20190610 或更新版本):

SslContextFactory.Client ssl = new SslContextFactory.Client(); // ssl config
ssl.setExcludeCipherSuites(); // blank out the default excluded cipher suites
WebSocketClient client = new WebSocketClient(ssl); // give ssl config to client

⚠️ WARNING: This is not recommended, and any modern computer (even cell phones) can easily read your encrypted traffic ⚠️警告:不建议这样做,任何现代计算机(甚至手机)都可以轻松读取您的加密流量

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM