WebSocket server does not work with SSL

2019-06-15 08:26发布

问题:

I have a working chat application using websockets. I want to go one step further and enable encryption on my connections, however when I switch up the http server with a https one my connections start failing.

I have generated a self-signed certificate that I use on all of my websites (under the same TLD, which implies it is a wildcard certificate). I can confirm it is a valid certificate, so the problem should not be there.

This is what works (unencrypted)

var webSocketServer = require('websocket').server;
var http = require('http');

var server = http.createServer(function() {});
server.listen(webSocketsServerPort, function () {
    log("system", "Server is listening on port " + webSocketsServerPort);
});

var wsServer = new webSocketServer({
    httpServer: server
});

Using this I can now connect to ws://my.domain:port.

This is what does not work

var webSocketServer = require('websocket').server;
var http = require('https');
var fs = require('fs');

var server = http.createServer({
    key: fs.readFileSync("path/to/host.key"),
    cert: fs.readFileSync("path/to/host.pem")
});
server.listen(webSocketsServerPort, function () {
    log("system", "Server is listening on port " + webSocketsServerPort);
});

var wsServer = new webSocketServer({
    httpServer: server
});

With this code the server starts as well, I see the log message "Server is listening.." but when I try to connect at wss://my.domain:port the connection can not be established.

I have added an exception in my browser for the certificate because my client page and websocket server address are under the same tld and sub-domain.

What could be the problem?

回答1:

It is not enough to add the site from which you'd like to connect to the websocket as exception. Go to the site https://my.domain:port (the websocket address) and add the location as exception. (It certainly is a necessary step in Firefox)

Alternatively you could import your certificate in the certificate manager into Authorities.

Edit: I can tell you what works for me.

> openssl genrsa -out key.pem
> openssl req -new -key key.pem -out csr.pem
> openssl x509 -req -days 9999 -in csr.pem -signkey key.pem -out cert.pem

setting the common name as localhost

in main.js

var https = require('https');
var ws = require('websocket').server;
var fs = require('fs');

var options = {
    key:fs.readFileSync('key.pem'),
    cert:fs.readFileSync('cert.pem')
};

var server = https.createServer(options,
    function(req,res){res.writeHeader(200);res.end();});
server.listen(8000);
var wss = new ws({httpServer:server});

wss.on('request',function(req){
    req.on('requestAccepted',function(conn){
        conn.on('message',function(msg){
            conn.send(msg.utf8Data + " received");
        });
    })
    req.accept(null,req.origin);
});

then in the browser(Firefox) at https://localhost:8000 (added cert as exception)

var ws = new WebSocket('wss://localhost:8000/')
ws.onmessage = function(msg){console.log(msg.data)}
ws.send("test")

and received test received.



回答2:

Bad practices combined with bad logging habits were the cause of the problem.

On opening a new connection there was a check performed to validate the origin of the request which had hardcoded http:// in there and since I was requesting it from a secure page (https://) the check no longer passed and connections were impossible.