Why does my wss:// (WebSockets over SSL/TLS) connection immediately disconnect without giving any errors?

Sven Slootweg picture Sven Slootweg · May 1, 2014 · Viewed 52k times · Source

Posting this for anybody else running across the same problem.

I was working on a browser client that used stanza.io to connect to an XMPP server (Prosody, in my case). I was using a wss:// connection by default. At some point during development, my client failed to connect at all - it would immediately disconnect silently, without providing any kind of useful error information.

There were no error logs, no error codes, no confirmation dialogs or bars, no indications of what might be wrong.

Answer

Sven Slootweg picture Sven Slootweg · May 1, 2014

After hours of debugging, I eventually found the problem; as I was messing around with the configuration of my XMPP server, I had re-generated the SSL certificates for the XMPPd. Since I was using self-signed certificates, this would cause an SSL error. Because I had visited that same URI over HTTPS before, I'd already manually approved the old self-signed certificate - but obviously that approval was no longer valid after regenerating the SSL certificate.

The key to the problem is this: If your SSL certificate causes a warning of any sort, wss:// WebSocket connections will immediately fail, and there is no canonical way to detect this.

As stated above, there appears to be no standardized way to even detect that this problem is occurring, let alone solve it. The best solution to this problem that I have been able to find, is as follows:

  1. If the WebSocket disconnects prior to having received a login confirmation (XMPP-specific), try to make a plaintext ws:// (without SSL) connection to the non-SSL port.
  2. If the plaintext connection succeeds, this means that the server is up - thus the problem is with the SSL certificate. (If the plaintext connection also fails, the server is simply unavailable.)
  3. Display an error to the user, indicating that there was an SSL problem, and that they should check the certificate, with instructions on how to manually approve it.
  4. Provide a target="_blank" link to the wss:// URL, but replacing the protocol with https://. This might be Prosody-specific, but by visiting that URL you will see the SSL warning page. Prosody will display a text that starts with "It works!" after approving the certificate - if the server-side is a custom application, you should display a message saying that "the problem has been solved, you can close this tab now".
  5. In the background, in the main application, keep attempting to reconnect over wss:// every few seconds. Once a connection succeeds, this means the user has approved the certificate. Hide/remove the error and continue the normal connection/login process.

It's far from a smooth process, UX-wise, but it's the smoothest approach I've found. It is not possible to iframe the error page (this was one of my first ideas) - Chrome will refuse to load it at all, Firefox will hide the "Add exception" button, and I'd imagine other browsers exhibit similar behaviour.