2

My development environment is this:

  • OS: Microsoft Windows 10
  • PHP framework: Laravel 8.0
  • PHP version 7.4
  • Websocket server: cboden/ratchet 0.4.3
  • WAMP server 3.2.0 (Apache 2.4.41)
  • Firefox 91.0.1 (64-bit) / chrome

I created a new Laravel app to implement a Secure Websocket Server and get connected to it using plain javascript on the client side (Laravel blade file). The websocket server works fine, as far as I can see it running, but the web browser is not able to connect, as seen on this image:

enter image description here

I have tried using different URLs, with and without port number, but to no avail. I created a SSL certificate and private key files, using openssl.exe tool, and put them in the command folder for testing purposes.

This is my handle code for the Secure Websocket Server:

   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();
   }

My virtual host in httpd-ssl.conf file:

<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>

The Apache modules proxy_module, proxy_http_module and proxy_wstunnel_module are loaded. The web app is running in HTTPS. Before, it was running over HTTP and WS and everything worked perfectly, but I need to secure this app and I am having issues to connect to the secure websocket server.

Am I missing something?

Is there something wrong with my Websocket server or Apache configuration?

jgarcias
  • 337
  • 3
  • 17
  • Kindly refer [this question](https://stackoverflow.com/q/14512182/13833218) – Rifky Niyas Aug 19 '21 at 03:59
  • 1
    Make sure `ssa` is registered as a DNS alias of wherever it's running at. If it's locally then usually you need to modify your hosts file – apokryfos Aug 19 '21 at 05:24
  • Yes @apokryfos, it is in the hosts file and the app runs fine with HTTP / WS protocols. – jgarcias Aug 19 '21 at 07:09
  • 1
    Try visiting `https://ssa` to approve the self-signed certificate in your browser and using `https://ssa` as your socket server and do not start the socket server as a secure server since you have the apache proxy running over https anyway. – apokryfos Aug 19 '21 at 07:38

3 Answers3

0

You are surely trying to connect to the wrong destination. It says wss:///ssa/wss/, but probably it should be wss://your.site.domain/ssa/wss/ .

So let's look at front end code and find out what's wrong with it.

0

Ok, as @apokryfos pointed out, I tried to proxy the websocket server through HTTPS but I was doing it in the wrong way.

I changed my websocket server to a non-secure one and did the following change to my virtual host:

<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>

On the client side, the browser can now contact the backend WS server through the HTTPS port:

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

I got this solution from Apache Config: Websockets Proxy WSS request to WS backend

Now I got my non-secure Websocket server sending/receiving through HTTPS. This is, for sure, not the solution I expected to apply to my needs but it certainly works. I still hope to find a formal solution to connecting plain JavaScript client to a Secure Websocket Server (wss://) without using a proxy mechanism.

jgarcias
  • 337
  • 3
  • 17
  • On Firefox, on the "Web Developer Tools" window, I checked the "Security" tab, because I saw no error details anywhere else, and there I found there is a MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT when I try to connect to my secure Websocket server. I have tried several work arounds I found here to allow the use of self signed certificates, but no luck yet for wss://:8443 – jgarcias Aug 24 '21 at 01:00
  • Ehmm... No, there is not any security warning as it used to happen with an HTTPS web page. I already went to check Firefox about:config and set network.stricttransportsecurity.preloadlist to "False" – jgarcias Aug 24 '21 at 01:37
  • In the Windows 10 Internet Options dialog box, I added my web application to the trusted sites, then I went again to about:config and set to "True" the value of the property **security.enterprise_roots.enabled** and restarted the browser. Now I get the error MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY – jgarcias Aug 24 '21 at 01:44
  • I decided to create another certificate using a config.conf file on the way, in which I specify **CA=false** to get rid with the last error message, because I am not a Certificate Authority to sign my local certificates and... it is curious to see it works from my Firefox console, but not from my JavaScript file using exactly the same url `var x = new WebSocket("wss://localhost:8443");`. What could be missing now? – jgarcias Aug 24 '21 at 08:54
0

For not to complicate my first answer with more information, here I provide the answer that really worked for me after all.

I created the Secure Websocket Server as follows:

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();
}

Note I changed the port number to 8443 (I don't think this has something to do) and also changed the certificate and key files for the new ones, generated as follows:

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

And the config.conf file is:

[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

All the difference lies in the last line CA=false to indicate I did not signed or acted as a Certificate Authority (CA). This gets rid of the MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY message.

Then, I got rid of the lines that defined the proxy in my httpd-ssl.conf file:

<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>

Please notice that for this virtual host I used the same certificate and key files I used for the Secure Websocket Server.

Ok, that was it for my certificate issue.

Now everything works as expected.

jgarcias
  • 337
  • 3
  • 17
  • It is important to remember to register the certificate in the "Manage computer Certificates" in the control panel (Windows 10), also do not forget to go to `about:config` and set the property `security.enterprise_roots.enabled` to `True`. – jgarcias Aug 24 '21 at 09:58
  • Well, after those changes it is necessary to restart the Apache server, the Websocket server and the Firefox browser... I decided to restart the computer, just in case. – jgarcias Aug 24 '21 at 10:51