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

jljoyd4f  于 2024-01-09  发布在  Java
关注(0)|答案(2)|浏览(347)

我需要使用Java连接到一个使用自签名证书的WebSocket服务器。我试图使用Jetty库,对Java很陌生,但我发现很难弄清楚需要做什么。我可以使用NodeJS非常简单地连接:

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

字符串
然而,修改我在Jetty docs上找到的示例并不能让我走得很远。
我实现了一个基本的客户端,它可以很好地与echo测试服务器一起工作,就像上面链接的例子一样。然后我继续用我自己的协议和IP地址配置它:

  1. private static void connectToBasestation() {
  2. // String destUri = "ws://echo.websocket.org";
  3. String basestationUri = "wss://192.168.100.220:9000/";
  4. SslContextFactory ssl = new SslContextFactory(); // ssl config
  5. ssl.setTrustAll(true); // trust all certificates
  6. WebSocketClient client = new WebSocketClient(ssl); // give ssl config to client
  7. BasestationSocket socket = new BasestationSocket();
  8. ArrayList<String> protocols = new ArrayList<String>();
  9. protocols.add("ws-valence");
  10. try
  11. {
  12. client.start();
  13. URI bsUri = new URI(basestationUri);
  14. ClientUpgradeRequest request = new ClientUpgradeRequest();
  15. request.setSubProtocols(protocols);
  16. client.connect(socket, bsUri, request);
  17. System.out.printf("Connecting to : %s%n", bsUri);
  18. // wait for closed socket connection.
  19. socket.awaitClose(5,TimeUnit.SECONDS);
  20. }
  21. catch (Throwable t)
  22. {
  23. t.printStackTrace();
  24. }
  25. finally
  26. {
  27. try
  28. {
  29. client.stop();
  30. }
  31. catch (Exception e)
  32. {
  33. e.printStackTrace();
  34. }
  35. }
  36. }


然而,我得到了一个UpgradeException,值为0 null,而我的onConnect方法从未被调用过。我猜这是一个安全问题,但我不能确定,因为服务器是一台旧机器-有点黑盒子。但我想也许我的方法有问题?有人能在这里提供一些建议吗?
编辑1:按照建议包含了可信的SSL工厂。它没有改变任何东西,包括下面的堆栈跟踪。
编辑3:上面列出了一个类似的问题,但这是不同的,因为1)我得到了一个不同的错误代码,2)添加一个可信的SSL工厂并不能解决问题。
编辑2:下面是我从OnError中获得的堆栈跟踪:

  1. Caused by: javax.net.ssl.SSLException: Received fatal alert: handshake_failure
  2. at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
  3. at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1666)
  4. at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1634)
  5. at sun.security.ssl.SSLEngineImpl.recvAlert(SSLEngineImpl.java:1800)
  6. at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:1083)
  7. at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:907)
  8. at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:781)
  9. at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
  10. at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.fill(SslConnection.java:681)
  11. at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.process(HttpReceiverOverHTTP.java:128)
  12. at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:73)
  13. at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:133)
  14. at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:155)
  15. at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:281)
  16. at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)
  17. at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:291)
  18. at org.eclipse.jetty.io.ssl.SslConnection$3.succeeded(SslConnection.java:151)
  19. at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)
  20. at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
  21. ... 3 more
  22. org.eclipse.jetty.websocket.api.UpgradeException: 0 null
  23. at org.eclipse.jetty.websocket.client.WebSocketUpgradeRequest.onComplete(WebSocketUpgradeRequest.java:522)
  24. at org.eclipse.jetty.client.ResponseNotifier.notifyComplete(ResponseNotifier.java:216)
  25. at org.eclipse.jetty.client.ResponseNotifier.notifyComplete(ResponseNotifier.java:208)
  26. at org.eclipse.jetty.client.HttpReceiver.terminateResponse(HttpReceiver.java:470)
  27. at org.eclipse.jetty.client.HttpReceiver.abort(HttpReceiver.java:552)
  28. at org.eclipse.jetty.client.HttpChannel.abortResponse(HttpChannel.java:156)
  29. at org.eclipse.jetty.client.HttpSender.terminateRequest(HttpSender.java:381)
  30. at org.eclipse.jetty.client.HttpSender.abort(HttpSender.java:566)
  31. at org.eclipse.jetty.client.HttpSender.anyToFailure(HttpSender.java:350)
  32. at org.eclipse.jetty.client.HttpSender$CommitCallback.failed(HttpSender.java:717)
  33. at org.eclipse.jetty.client.http.HttpSenderOverHTTP$HeadersCallback.failed(HttpSenderOverHTTP.java:310)
  34. at org.eclipse.jetty.io.WriteFlusher$PendingState.fail(WriteFlusher.java:263)
  35. at org.eclipse.jetty.io.WriteFlusher.onFail(WriteFlusher.java:516)
  36. at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint$FailWrite.run(SslConnection.java:1251)
  37. at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:762)
  38. at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:680)
  39. at java.lang.Thread.run(Thread.java:748)

uajslkp6

uajslkp61#

TLS/SSL握手错误是相当常见的。
您不知道问题发生在TLS/SSL握手的哪个部分。
您可以在Java上使用-Djavax.net.debug=all命令行选项来查看TLS/SSL握手的原始细节,这可能是开始解决问题的好地方。
一些选择...

证书名称问题

如果您连接到服务器,并且提供的证书与您在URI中用于连接的主机名不匹配,则这违反了Java本身的端点标识算法。
示例场景:
1.连接到wss://192.168.1.0:8443/chat
1.证书报告自身为chatserver.acme.com
这是一个违规行为,因为URI 192.168.1.0中的主机名与证书chatserver.acme.com不匹配
这在使用wss://localhostwss://127.0.0.1进行测试时尤其常见
您可以告诉Java不要像这样执行端点标识检查.

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

字符串

恶意 攻击:不推荐使用,容易造成中间人攻击!

证书信任问题

尝试为所有证书启用信任。
1.为WebSocket客户端启用SSL/TLS
1.信任SSL/TLS配置上的所有证书
示例(假设Jetty 9.4.19.v20190610或更新版本):

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

恶意 攻击:不推荐使用,容易造成中间人攻击!

证书算法问题

用于创建证书的算法将限制TLS/SSL握手期间可用的密码套件。
例如,如果服务器只有DSA证书(已知易受攻击),则RSA或ECDSA证书都不可用。
用于创建证书的位数也是相关的,因为如果服务器证书太少,那么Java本身将拒绝它。
如果您控制服务器证书,请确保您生成的证书包含RSA和ECDSA证书,RSA至少有2048位(或更多),ECDSA至少有256位。

针对密码套件问题

在码头那边尝试一个空的密码套件排除列表。

**密码:这允许您使用已知易受攻击的密码套件!**️

1.为WebSocket客户端启用SSL/TLS
1.清空密码套件排除列表
示例(假设Jetty 9.4.19.v20190610或更新版本):

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

加密:不建议这样做,任何现代计算机(甚至手机)都可以轻松读取您的加密流量

展开查看全部
jfewjypa

jfewjypa2#

  1. // ...
  2. new WebSocketClient(ssl);

字符串
从Jetty 10开始,这种语法不再起作用。
对于Jetty 10,由Jetty 10 WebSocketClientServlet.java测试提供:

  1. SslContextFactory.Client ssl = new SslContextFactory.Client(true);
  2. ClientConnector connector = new ClientConnector();
  3. clientConnector.setSslContextFactory(ssl);
  4. HttpClient http = new HttpClient(new HttpClientTransportOverHTTP(connector));
  5. WebSocketClient client = new WebSocketClient(http);

相关问题