无法与 javascript 建立连接到安全的 websocket 服务器

Can't establish a connection with javascript to a secure websocket server

我的开发环境是这样的:

我创建了一个新的 Laravel 应用程序来实现安全 Websocket 服务器,并在客户端使用纯 javascript 连接到它(Laravel blade 文件) . 据我所知,websocket 服务器工作正常 运行,但网络浏览器无法连接,如下图所示:

我试过使用不同的 URL,有和没有端口号,但都无济于事。 我使用 openssl.exe 工具创建了一个 SSL 证书和私钥文件,并将它们放在命令文件夹中以供测试。

这是我的安全 Websocket 服务器句柄代码:

   public function handle()
   {
      $loop   = Factory::create();
      $webSock = new SecureServer(
         new Server('0.0.0.0:8090', $loop),
         $loop,
         array(
            'local_cert'        => 'certificate.crt', 
            'local_pk'          => 'private.key', 
            'allow_self_signed' => TRUE, 
            'verify_peer' => FALSE
         )
      );

      // Ratchet magic
      $webServer = new IoServer(
         new HttpServer(
            new WsServer(
               new WebSocketController()
            )
         ),
         $webSock
      );

      $loop->run();
   }

我在 httpd-ssl.conf 文件中的虚拟主机:

<VirtualHost *:443>
  ServerName ssa
  DocumentRoot "d:/web/app/ssa/public"
  SSLEngine on
  
  SSLCertificateFile "${SRVROOT}/conf/certificate.crt"
  SSLCertificateKeyFile "${SRVROOT}/conf/private.key"

  SSLVerifyClient none
  SSLVerifyDepth 10

  <Directory "d:/web/app/ssa/public">
    Options +Indexes +Includes +FollowSymLinks +MultiViews
    AllowOverride All
    Require local
  </Directory>
  
  ProxyRequests Off 
  ProxyPass /wss/  ws://ssa:8090
</VirtualHost>

已加载 Apache 模块 proxy_module、proxy_http_module 和 proxy_wstunnel_module。 Web 应用程序在 HTTPS 中是 运行。 之前,它是通过 HTTP 和 WS 运行 并且一切正常,但我需要保护这个应用程序并且我在连接到安全的 websocket 服务器时遇到问题。

我是不是漏掉了什么?

我的 Websocket 服务器或 Apache 配置有问题吗?

您肯定尝试连接到错误的目的地。它说 wss:///ssa/wss/,但可能应该是 wss://your.site.domain/ssa/wss/ .

所以让我们看一下前端代码,看看它有什么问题。

好的,正如@apokryfos 所指出的,我尝试通过 HTTPS 代理 websocket 服务器,但我以错误的方式进行。

我将我的 websocket 服务器更改为不安全的,并对我的虚拟主机进行了以下更改:

<VirtualHost *:443>
  ServerName ssa
  DocumentRoot "d:/web/app/ssa/public"
  SSLEngine on
  
  SSLCertificateFile "${SRVROOT}/conf/certificate.crt"
  SSLCertificateKeyFile "${SRVROOT}/conf/private.key"

  SSLVerifyClient none
  SSLVerifyDepth 10

  <Directory "d:/web/app/ssa/public">
    Options +Indexes +Includes +FollowSymLinks +MultiViews
    AllowOverride All
    Require local
  </Directory>
  
  Redirect /wss /wss/
  ProxyPass /wss/ ws://127.0.0.1:8090/
  ProxyPassReverse /ws/ wss://127.0.0.1:8090/
</VirtualHost>

在客户端,浏览器现在可以通过HTTPS端口联系后端WS服务器:

// The connection to the WebSocket Server.
var socket = new WebSocket("wss://ssa:443/wss/");

我从 Apache Config: Websockets Proxy WSS request to WS backend

现在我通过 HTTPS 获得了我的非安全 Websocket 服务器 sending/receiving。 当然,这不是我期望应用于我的需求的解决方案,但它确实有效。 我仍然希望找到一个正式的解决方案,在不使用代理机制的情况下将普通 JavaScript 客户端连接到安全 Websocket 服务器 (wss://)。

为了不让我的第一个答案复杂化,提供更多信息,我在这里提供毕竟对我真正有用的答案。

我按如下方式创建了安全 Websocket 服务器:

public function handle() {
      $loop = Factory::create();
      $webSock = new SecureServer(
         new Server('0.0.0.0:8443', $loop),
         $loop,
         array(
            'local_cert' => 'C:/wamp64/bin/apache/apache2.4.41/conf/server.crt',
            'local_pk' => 'C:/wamp64/bin/apache/apache2.4.41/conf/server.key', 
            'allow_self_signed' => TRUE, 
            'verify_peer' => FALSE
         )
      );
      $webServer = new IoServer(
         new HttpServer(
            new WsServer(
               new WebSocketController()
            )
         ),
         $webSock
      );
      $loop->run();
}

注意我把端口号改成了8443(我觉得这没啥关系),也把证书和密钥文件改成了新的,生成如下:

openssl req -config config.conf -new -x509 -out server.crt -days 3650

config.conf 文件是:

[req]
default_bits = 2048
encrypt_key = no
default_md = sha256
default_keyfile = server.key
distinguished_name = req_distinguished_name
prompt = no

[req_distinguished_name]
C = KH
ST = Siem Reap
L = SR
O = AHC
OU = IT
CN = localhost

[bs_section]
CA=false

所有不同之处在于最后一行 CA=false 表明我没有签署或充当证书颁发机构 (CA)。 这摆脱了 MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY 消息。

然后,我删除了在我的 httpd-ssl.conf 文件中定义代理的行:

<VirtualHost *:443>
  ServerName ssa
  DocumentRoot "d:/web/app/ssa/public"
  SSLEngine on
  
  SSLCertificateFile "${SRVROOT}/conf/server.crt"
  SSLCertificateKeyFile "${SRVROOT}/conf/server.key"

  SSLVerifyClient none
  SSLVerifyDepth 10

  <Directory "d:/web/app/ssa/public">
    Options +Indexes +Includes +FollowSymLinks +MultiViews
    AllowOverride All
    Require local
  </Directory>
  
  #Redirect /wss /wss/
  #ProxyPass /wss/ ws://127.0.0.1:8090/
  #ProxyPassReverse /ws/ wss://127.0.0.1:8090/
</VirtualHost>

请注意,对于这个虚拟主机,我使用了与安全 Websocket 服务器相同的证书和密钥文件。

好的,这就是我的证书问题。

现在一切正常。