Jump to content
whatsmyname

Websockets will not work over TLS/SSL

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

Share this post


Link to post
Share on other sites

Do you have a WebSocket-enabled server ready on port 8443?

Share this post


Link to post
Share on other sites
2 hours ago, requinix said:

Do you have a WebSocket-enabled server ready on port 8443?

Hello. Yes, the server is started via command line e.g. 'php server.php'

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

Share this post


Link to post
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?

Share this post


Link to post
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

Share this post


Link to post
Share on other sites

Are you running all this on your local server, or is any part of it deployed remotely?

Share this post


Link to post
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?

Share this post


Link to post
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?

Share this post


Link to post
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();

 

Share this post


Link to post
Share on other sites

Have you tried running post.php twice? Does the second time work?

If you restart the server and then don't do anything else, can you connect with telnet then?

Share this post


Link to post
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.

Share this post


Link to post
Share on other sites

Make sure you have something set up to handle errors on the server side of things. Like your Pusher::onError is empty.

Share this post


Link to post
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

Share this post


Link to post
Share on other sites

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.