Jump to content

Websockets will not work over TLS/SSL


whatsmyname

Recommended Posts

I've finally got the time to learn web sockets and have choosen to use: http://socketo.me/docs/push to do so. It all works perfectly fine without SSL. The moment it's enabled the client javascript will not connect and will output "WebSocket opening handshake timed out". I've tried the server with and without the TLS options.

client.html, post.php, server.php

<script type="text/javascript" src="autobahn.js"></script>
<script>

 
    var conn = new ab.Session('wss://domain.com:8443',
        function() {
console.log('Connected');            
conn.subscribe('kittensCategory', function(topic, data) {
                // This is where you would add the new article to the DOM (beyond the scope of this tutorial)
                console.log('New article published to category "' + topic + '" : ' + data.title);
            });
        },
        function() {
            console.warn('WebSocket connection closed');
        },
        {'skipSubprotocolCheck': true}
    );

</script>
<?php
require dirname(__DIR__) . '/socket/vendor/autoload.php';

// post.php ???
    // This all was here before  ;)
    $entryData = array(
        'category' => 'kittensCategory'
      , 'title'    => 'My Impressive Title'
      , 'article'  => 'Just me the best, nothing new!'
      , 'when'     => time()
    );

    // This is our new stuff
    $context = new ZMQContext();
    $socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'my pusher');
    $socket->connect("tcp://localhost:5555");

    $socket->send(json_encode($entryData));
	
	echo 'All Sent!';
<?php

require dirname(__DIR__) . '/socket/vendor/autoload.php';

use Ratchet\ConnectionInterface;
use Ratchet\Wamp\WampServerInterface;

class Pusher implements WampServerInterface {
   
    /**
     * A lookup of all the topics clients have subscribed to
     */
    protected $subscribedTopics = array();

    public function onSubscribe(ConnectionInterface $conn, $topic) {
echo 'Subbed';       
 $this->subscribedTopics[$topic->getId()] = $topic;
    }

    /**
     * @param string JSON'ified string we'll receive from ZeroMQ
     */
    public function onBlogEntry($entry) {
		
		echo 'Hello!';
		
        $entryData = json_decode($entry, true);

        // If the lookup topic object isn't set there is no one to publish to
        if (!array_key_exists($entryData['category'], $this->subscribedTopics)) {
            return;
        }

        $topic = $this->subscribedTopics[$entryData['category']];

        // re-send the data to all the clients subscribed to that category
        $topic->broadcast($entryData);
    }

    /* The rest of our methods were as they were, omitted from docs to save space */
	
	
	//public function onSubscribe(ConnectionInterface $conn, $topic) {
   // }
    public function onUnSubscribe(ConnectionInterface $conn, $topic) {
    }
    public function onOpen(ConnectionInterface $conn) {
    }
    public function onClose(ConnectionInterface $conn) {
    }
    public function onCall(ConnectionInterface $conn, $id, $topic, array $params) {
        // In this application if clients send data it's because the user hacked around in console
        $conn->callError($id, $topic, 'You are not allowed to make calls')->close();
    }
    public function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible) {
        // In this application if clients send data it's because the user hacked around in console
        $conn->close();
    }
    public function onError(ConnectionInterface $conn, \Exception $e) {
    }
}

	

    $loop   = React\EventLoop\Factory::create();
    $pusher = new Pusher;

    // Listen for the web server to make a ZeroMQ push after an ajax request
    $context = new React\ZMQ\Context($loop);
    $pull = $context->getSocket(ZMQ::SOCKET_PULL);
    $pull->bind('tcp://127.0.0.1:5555'); // Binding to 127.0.0.1 means the only client that can connect is itself
    $pull->on('message', array($pusher, 'onBlogEntry'));

    // Set up our WebSocket server for clients wanting real-time updates
    $webSock = new React\Socket\Server('0.0.0.0:8443', $loop, array(
    'tls' => array(
        'local_cert' => 'cert.pem',
	'local_pk'    => 'private.key', // path to your server private key,
        'verify_peer' => FALSE

    ))); // Binding to 0.0.0.0 means remotes can connect
	
    $webServer = new Ratchet\Server\IoServer(
        new Ratchet\Http\HttpServer(
            new Ratchet\WebSocket\WsServer(
                new Ratchet\Wamp\WampServer(
                    $pusher
                )
            )
        ),
        $webSock
    );

    $loop->run();

 

Edited by whatsmyname
Link to comment
Share on other sites

3 minutes ago, whatsmyname said:

The server is working as 'post.php' is sending messages but the client.html JavaScript is not.

I may be misreading, but isn't post.php is connecting to port 5555? And over TCP without the SSL layer?

Link to comment
Share on other sites

Your not misreading it indeed is.

I'm using a library called ZMQ which posts to the server side ZMQ this then sends the data to the actual socket server. It allows for things like subscribe to notifications. If you stripped all this back and used the most basic "Hello World" located here "http://socketo.me/docs/hello-world" - This is what it looks like without ZMQ.

This also does not like to run over TLS/SSL. My scripts above are from here: "http://socketo.me/docs/push"

I'm so stumbled right now, I really am. "WebSocket opening handshake timed out"

I've even posted on stack overflow: https://stackoverflow.com/questions/58762640/websockets-will-not-work-over-tls-ssl-but-will-work-without

Link to comment
Share on other sites

I've ran this on XAMPP locally and on Centos 7 remotely deployed both of which the javascript will timeout on handshake. The remote has a valid SSL certificate and domain name. I've also gone as far as disabling the firewall to make sure this was not an issue. I take it you have experience in websockets?

Link to comment
Share on other sites

For the most part.

The timeout is happening for one of two reasons: it can't connect at all, or it can connect but the server was there but somehow able to complete the handshake. The latter is unlikely.

- Can you manually telnet to the port? To test whether you can connect at all. Run post.php and confirm the server received the message, telnet, and run post.php again.
- What does the browser show for the WSS connection in its networking request monitoring thing?

Link to comment
Share on other sites

Thanks for sticking around @requinix

Running post.php does trigger (onBlogEntry) which outputs "Hello!"

Tried to telnet into the remote deployed version and telnet outputted "Connecting To host...Could not open connection to the host, on port x.x.x.x:8443: Connect failed"

I then tried it locally (Windows):
Connecting To host...Could not open connection to the host, on port 127.0.0.1:8443: Connect failed

I then tried to telnet into their basic hello world example as follows: Connecting To host...Could not open connection to the host, on port 127.0.0.1:8080: Connect failed.

Just to confirm, both servers was running at the time of telnet and the firewall was disabled.

<?php

require dirname(__DIR__) . '/socket/vendor/autoload.php';

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class Chat implements MessageComponentInterface {
    protected $clients;

    public function __construct() {
        $this->clients = new \SplObjectStorage;
    }

    public function onOpen(ConnectionInterface $conn) {
        // Store the new connection to send messages to later
        $this->clients->attach($conn);

        echo "New connection! ({$conn->resourceId})\n";
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        $numRecv = count($this->clients) - 1;
        echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n"
            , $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');

        foreach ($this->clients as $client) {
            if ($from !== $client) {
                // The sender is not the receiver, send to each client connected
                $client->send($msg);
            }
        }
    }

    public function onClose(ConnectionInterface $conn) {
        // The connection is closed, remove it, as we can no longer send it messages
        $this->clients->detach($conn);

        echo "Connection {$conn->resourceId} has disconnected\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "An error has occurred: {$e->getMessage()}\n";

        $conn->close();
    }
}

use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;

    $server = IoServer::factory(
        new HttpServer(
            new WsServer(
                new Chat()
            )
        ),
        8080
    );

    $server->run();

 

Link to comment
Share on other sites

Just a quick update! telnet is working and does connect to both deployment and local. - I didn't write the host name and port correctly.

HOWEVER both of which eventually times out also:

HTTP/1.1 500 Internal Server Error 

X-Powered-By: Ratchet/0.4.1                                                                                                                                                                                                                     

Connection to host lost.

- Will check logs now.

Link to comment
Share on other sites

SOLUTION:

In order for the client to work over SSL you need to set the server certificate and private key and start a secure server as follows.

Quote

$loop = React\EventLoop\Factory::create();
$pusher = new MyApp\Pusher;

// Listen for the web server to make a ZeroMQ push after an ajax request
$context = new React\ZMQ\Context($loop);
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5555'); // Binding to 127.0.0.1 means the only client that can connect is itself
$pull->on('message', [$pusher, 'onUpdate']);

// Set up our WebSocket server for clients wanting real-time updates
$webSock = new React\Socket\Server('0.0.0.0:8443', $loop);
$webSock = new React\Socket\SecureServer($webSock, $loop, [
    'local_cert'        => 'C:/xampp/apache/conf/ssl.crt/server.crt', // path to your cert
    'local_pk'          => 'C:/xampp/apache/conf/ssl.key/server.key', // path to your server private key
    'allow_self_signed' => TRUE, // Allow self signed certs (should be false in production)
    'verify_peer' => FALSE
]);
//$webSock->listen(8443, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
$webServer = new Ratchet\Server\IoServer(
    new Ratchet\Http\HttpServer(
        new Ratchet\WebSocket\WsServer(
            new Ratchet\Wamp\WampServer(
                $pusher
            )
        )
    ),
    $webSock
);

$loop->run();

Please see here:
https://github.com/ratchetphp/Ratchet/issues/609#issuecomment-363743604

Edited by whatsmyname
  • Like 1
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.