Laravel-websockets: Chrome not working with SSL

Created on 30 May 2019  路  16Comments  路  Source: beyondcode/laravel-websockets

So I have 2 servers setup with Digital Ocean, both running Ubuntu 18.04 and apache. Certbot is used to install Let's Encrypt SSL certificates on both servers. Websockets was working well with supervisord running the websocket server until SSL certificates were installed on each server. I followed the documentation and even watched this videos for good measure to configure websockets with SSL.

However, Chrome always gives throws a WebSocket opening handshake was cancelled error when I try connecting to the dashboard or visit a route using websockets. This error only occurs in Chrome.

I found this issue which is an exact replica but unfortunately, it was closed as it somehow resolved itself automagically when another server was provisioned using Forge. I do not have access to Forge so this isn't an option.

To solve this, I added 'curl_options' => [ CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ], to config/broadcasting.php and also set 'verify_peer' => false, in config/websockets.php. But this comment strongly advises against this.

Someone please help out; I'm at my wits end.

'pusher' => [
            'driver'  => 'pusher',
            'key'     => env('PUSHER_APP_KEY'),
            'secret'  => env('PUSHER_APP_SECRET'),
            'app_id'  => env('PUSHER_APP_ID'),
            'options' => [
                'cluster'      => env('PUSHER_APP_CLUSTER'),
                'encrypted'    => true,
                'host'         => '127.0.0.1',
                'port'         => 6001,
                'scheme'       => 'https',
                'curl_options' => [
                    CURLOPT_SSL_VERIFYHOST => 0,
                    CURLOPT_SSL_VERIFYPEER => 0,
                ],
            ],
        ],
'ssl' => [        
        'local_cert' => env('LOCAL_CERT_FILE', null),       
        'local_pk' => env('LOCAL_PRIVATE_KEY', null),        
        'passphrase' => null,
        'verify_peer' => false,
    ],
import Echo from 'laravel-echo'

window.Pusher = require('pusher-js');

window.Echo = new Echo({
    broadcaster: 'pusher',
    encrypted: true,
    key: process.env.MIX_PUSHER_APP_KEY,
    wsHost: window.location.hostname,
    wsPort: 6001,
    wssPort: 6001,
    disableStats: true,
    enabledTransports: ['ws', 'wss'],
});
LOCAL_CERT_FILE='/etc/letsencrypt/live/example.com/fullchain.pem'
LOCAL_PRIVATE_KEY='/etc/letsencrypt/live/example.com/privkey.pem'

Thanks

All 16 comments

We have the exact same problem on our project. Let's Encrypt certificate for wildcard subdomains. The only fix working is to disable verify_peer.

Works properly in Firefox and Safari. Chrome fails though.

Would be happy to get input too, we are running out of ideas. Thanks anyway for the awesome package.

Hey @simioluwatomi . Could you solve this? i have the same problem

i hame same problem :/

Same problem here, someone find a fix. Having this issue with a Let's Encrypt certificate.

The same. Firefox ok, Chrome drops handshake :( Let'sencrypt cert, not wildcard, single domain

Yeah there seems to be an issue with Chrome at the moment with this. Works fine on Firefox but chrome keeps dropping the connection.

Same issue, nothing in the documentation works for chrome, initial handshake fails; works fine on safari and firefox.

Same problem here. Any solution?

A solution to the 'WebSocket opening handshake was cancelled' error, in chrome for wss/ssl connections.

I struggled with this too and finally identified the cause.
I Hope this helps, so you too can enjoy secure php websockets in laravel!
(thank you @beyondcode, an @laravel an @react .. :)


You can verify the issue and solution by trying to access your socket server directly in chrome. eg.

  1. Go to https://www.yourwebsite.com:6001 in the browser.
  2. You should see the client certificate dialog appear.
  3. Choose a certificate if you are using client certs, or press cancel if not.
  4. and then try reconnecting to your socket server, hopefully you're successful.

When you initiate a TLS connection in chrome, to a socket server that accepts or requires client certificates.
The websocket connection is classed 'non-interactive', but requires a user choice for the client cert, so chrome doesn't show the dialog and aborts.

More details: Issue 329884: Secure Websocket with client certificate not working

Related Issue: Chrome cannot connect via wss; returns error "WebSocket opening handshake was canceled"

The php implementation of SSL, which react uses behind the scenes, doesn't let you configure the SSLVerifyClient directive context.ssl.php.
So it looks like php's ssl allows for client certificates by default, and chrome will just block those unless you have previously made a choice in the SSL client certificate dialog.

Solutions:

The only option in my situation seems to be to proxy (and not use phps ssl).

  1. proxy via 443 or another port, so the SSLVerifyClient directive can be removed.

If you are using client certificates, and your web and socket server are on the same domain, any client cert choice should already be satisfied and you shouldn't have this problem.

It would be nice to use the secure socket server directly without a proxy service, if anyone has a better idea of how to work around this please let us know! :)

--

To reiterate the point above and disabling 'verify_peer'.

"I would really advise anyone to NOT disable VERIFYHOST and VERIFYPEER, that's just throwing away all the security HTTPS provides." reference

Here's what I added to apache config to add the proxy service. This fixed the issue with Chrome. Thanks FfionTree!

<Proxy "https://mysite.domain*">
SSLProxyMachineCertificateFile /some/path
</Proxy>

Update: Websockets were working for Chrome after adding this directive and restarting Apache. I killed the websockets process with Supervisor so that I could run them in the console to do some debugging on the js code I was writing and then Chrome stopped working again. I havn't been able to get back to the state where Chrome was working. Ugh! Very frustrating. Safari and Firefox work. Why can't can't Chrome play nice?!!

A solution to the 'WebSocket opening handshake was cancelled' error, in chrome for wss/ssl connections.

I struggled with this too and finally identified the cause.
I Hope this helps, so you too can enjoy secure php websockets in laravel!
(thank you @beyondcode, an @laravel an @react .. :)

You can verify the issue and solution by trying to access your socket server directly in chrome. eg.

  1. Go to https://www.yourwebsite.com:6001 in the browser.
  2. You should see the client certificate dialog appear.
  3. Choose a certificate if you are using client certs, or press cancel if not.
  4. and then try reconnecting to your socket server, hopefully you're successful.

When you initiate a TLS connection in chrome, to a socket server that accepts or requires client certificates.
The websocket connection is classed 'non-interactive', but requires a user choice for the client cert, so chrome doesn't show the dialog and aborts.

More details: Issue 329884: Secure Websocket with client certificate not working

Related Issue: Chrome cannot connect via wss; returns error "WebSocket opening handshake was canceled"

The php implementation of SSL, which react uses behind the scenes, doesn't let you configure the SSLVerifyClient directive context.ssl.php.
So it looks like php's ssl allows for client certificates by default, and chrome will just block those unless you have previously made a choice in the SSL client certificate dialog.

Solutions:

The only option in my situation seems to be to proxy (and not use phps ssl).

  1. proxy via 443, so any client cert choice is already satisfied.
  2. proxy via any port, so the SSLVerifyClient directive can be removed.

It would be nice to use the secure socket server directly without a proxy service, if anyone has a better idea of how to work around this please let us know! :)

--

To reiterate the point above and disabling 'verify_peer'.

"I would really advise anyone to NOT disable VERIFYHOST and VERIFYPEER, that's just throwing away all the security HTTPS provides." reference

@FfionTree can you explain further how you how you setup the proxy?

Hi Robert
Generally speaking, the easiest way to setup a proxy would be to use nginx, mainly because it is better documented:

You can do the same thing with other servers inc apache but you have to google and piece together a solution, which is more difficult as you found. Its possible to do though, so keep trying.

Sorry I don't have a good example for how to setup apache, I'm still considering my options.
It could be worth opening up a ticket to create some 'apache proxy setup documentation' and crowdsource some working examples.

any solution I have the same issue and not able to work on chrome failed: WebSocket opening handshake was canceled

Me too. Any solution will be appreciated

Make sure the key and certificate are readable in the UNIX filesystem.

A solution to the 'WebSocket opening handshake was cancelled' error, in chrome for wss/ssl connections.

I struggled with this too and finally identified the cause.
I Hope this helps, so you too can enjoy secure php websockets in laravel!
(thank you @beyondcode, an @laravel an @react .. :)

You can verify the issue and solution by trying to access your socket server directly in chrome. eg.

  1. Go to https://www.yourwebsite.com:6001 in the browser.
  2. You should see the client certificate dialog appear.
  3. Choose a certificate if you are using client certs, or press cancel if not.
  4. and then try reconnecting to your socket server, hopefully you're successful.

When you initiate a TLS connection in chrome, to a socket server that accepts or requires client certificates.
The websocket connection is classed 'non-interactive', but requires a user choice for the client cert, so chrome doesn't show the dialog and aborts.

More details: Issue 329884: Secure Websocket with client certificate not working

Related Issue: Chrome cannot connect via wss; returns error "WebSocket opening handshake was canceled"

The php implementation of SSL, which react uses behind the scenes, doesn't let you configure the SSLVerifyClient directive context.ssl.php.
So it looks like php's ssl allows for client certificates by default, and chrome will just block those unless you have previously made a choice in the SSL client certificate dialog.

Solutions:

The only option in my situation seems to be to proxy (and not use phps ssl).

  1. proxy via 443 or another port, so the SSLVerifyClient directive can be removed.

If you are using client certificates, and your web and socket server are on the same domain, any client cert choice should already be satisfied and you shouldn't have this problem.

It would be nice to use the secure socket server directly without a proxy service, if anyone has a better idea of how to work around this please let us know! :)

--

To reiterate the point above and disabling 'verify_peer'.

"I would really advise anyone to NOT disable VERIFYHOST and VERIFYPEER, that's just throwing away all the security HTTPS provides." reference

By reading your detailed solution, i have resolved my issue :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ahmed-aliraqi picture ahmed-aliraqi  路  4Comments

AMINEDGE picture AMINEDGE  路  3Comments

connecteev picture connecteev  路  3Comments

stefandanaita picture stefandanaita  路  4Comments

rikless picture rikless  路  4Comments