簡體   English   中英

在java中使用自簽名證書連接到websocket

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

我需要使用 Java 連接到使用自簽名證書的 WebSocket 服務器。 我正在嘗試使用 Jetty 庫,並且在 Java 方面還是很新的,但我發現很難弄清楚需要做什么。 我可以非常簡單地使用 NodeJS 進行連接:

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

但是,修改我在Jetty 文檔上找到的示例並沒有讓我走得很遠。

我實現了一個與回聲測試服務器配合良好的基本客戶端,就像上面鏈接的例子一樣。 然后我繼續用我自己的協議和 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();

        }
    }
  }

但是,我收到了一個UpgradeException 0 nullUpgradeException ,並且我的onConnect方法永遠不會被調用。 我猜這是一個安全問題,但我不能確定,因為服務器是一台舊機器——有點像黑匣子。 但我在想也許我的方法有問題? 任何人都可以在這里提供任何建議嗎?

編輯 1:按照建議包含可信任的 SSL 工廠。 它沒有改變任何東西,包括下面的堆棧跟蹤。

編輯 3:上面列出了一個類似的問題,但這是不同的,因為 1) 我收到了不同的錯誤代碼 2) 添加可信任的 SSL 工廠並不能解決問題。

編輯 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)

TLS/SSL 握手錯誤相當普遍。

您不知道問題發生在 TLS/SSL 握手的哪個部分。

您可以在 Java 上使用-Djavax.net.debug=all命令行選項來查看 TLS/SSL 握手的原始詳細信息,這可能是開始解決問題的好地方。

一些選擇...


對於證書名稱問題

如果您連接到服務器並且提供的證書與您在 URI 中用於連接的主機名不匹配,則這違反了 Java 本身中存在的端點識別算法。

示例場景:

  1. 您連接到wss://192.168.1.0:8443/chat
  2. 證書將自身報告為chatserver.acme.com

這是違規行為,因為 URI 192.168.1.0中的主機名與證書chatserver.acme.com不匹配

這在使用wss://localhostwss://127.0.0.1測試時尤其常見

你可以告訴 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

⚠️警告:不推薦這樣做,很容易被中間人攻擊!


對於證書信任問題

嘗試為所有證書啟用信任。

  1. 為 WebSocket 客戶端啟用 SSL/TLS
  2. 信任 SSL/TLS 配置上的所有證書

示例(假設 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

⚠️警告:不推薦這樣做,很容易被中間人攻擊!


對於證書算法問題

用於創建證書的算法將限制在 TLS/SSL 握手期間可用的可用密碼套件。

例如,如果服務器只有一個 DSA 證書(已知易受攻擊的證書),那么 RSA 或 ECDSA 證書都不可用。

用於創建證書的位數也是相關的,好像服務器證書太少了,那么 Java 本身就會拒絕它。

如果您控制服務器證書,請確保您已生成包含 RSA 和 ECDSA 證書的證書,其中至少 2048 位用於 RSA(或更多),256 位用於 ECDSA。


對於密碼套件問題

在 Jetty 端嘗試一個空的密碼套件排除列表。

⚠️ 警告:這讓您可以使用已知的易受攻擊的密碼套件!

  1. 為 WebSocket 客戶端啟用 SSL/TLS
  2. 清除密碼套件排除列表

示例(假設 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

⚠️警告:不建議這樣做,任何現代計算機(甚至手機)都可以輕松讀取您的加密流量

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM