arthurkushman / php-wss

Web-socket server/client with multi-process and parse templates support on server and send/receive options on client
MIT License
209 stars 32 forks source link

SSL Support #51

Closed SimoleS closed 3 years ago

SimoleS commented 3 years ago

Hello, I want to ask if is possible to configure server with SSL certs. Or i need to hide it behind server. Thanks.

arthurkushman commented 3 years ago

Hi, I think for now it is of need to hide ssl behind server, because php-wss only supports SSL connection via client. Although, it would be great to implement this feature in perspective. (Suppose that many devs use proxy/reverse-proxy solutions for that purpose)

saschi123 commented 3 years ago

Hi, the dirty fix, add/change in WebSocketServer.php

$context = stream_context_create();
 stream_context_set_option($context, 'ssl', 'allow_self_signed', true);
        stream_context_set_option($context, 'ssl', 'verify_peer', false);
        stream_context_set_option($context, 'ssl', 'local_cert', '/etc/letsencrypt/live/exampletls/fullchain.pem');
        stream_context_set_option($context, 'ssl', 'local_pk', '/etc/letsencrypt/live/exampletls/privkey.pem');

        $server = stream_socket_server("tls://{$this->config->getHost()}:{$this->config->getPort()}", $errno, $errorMessage, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context);

Overwrite Line 70/71 with this. and change the local_cert and local_pk path to yours.

arthurkushman commented 3 years ago

@saschi123 thank u for proposition, I'll try to implement this by adding those options for allow_self_signed, verify_peer, local_cert and local_pk into ServerConfig and pass it through $context, as soon as I have time for that.

arthurkushman commented 3 years ago

Just leave it here, for anyone who will want to dig further into analysis in SSL over HTTP under php streams API (the top comment from php dot net):

I'm writing an HTTP server and I need SSL support, but getting this to work correctly with PHP streams took a bit of trial and error. For anyone who is trying to get an HTTP SSL server working with stream_socket_server:

1) Your SSL context will need to contain 'local_cert'. If you did not include your private key with your local_cert, you'll also need to specify 'local_pk' which is your RSA key. Your keys and certs should be PEM encoded, which means base-64. If your certificate has intermediary certs, you will need to specify those in the correct order: Your signed cert, intermediary cert 1, intermediary cert 2, etc. Each cert in the list needs to validate the one above it, but you do not need to include the CA Root that your SSL signer provided; that should already be included with the client's software (i.e. trust root certs).

You can append your private key in the file with your certs, however I keep mine in its own file. If you see the word "encrypted" when you view your key with a text viewer, you need to enter the correct passphrase and specify the context "passphrase", otherwise you can leave that one out.

As a server, verify_peer is irrelevant and should be set to false (should always be true if you are acting as an SSL client). Both cafile and capath contexts are not needed for functioning as a SSL/TLS server, but they are needed if you are making SSL connections with PHP as the client.

Lastly, the 'ciphers' context should be set to a list of secure ciphers. Search for "mozilla recommended ciphers" and choose the string of ciphers that works for you, because not all openssl supported ciphers are secure. I went with the "intermediate" list, which provides high security and compatibility.

2) When you create the binding for stream_socket_server(), make sure that you choose the tcp:// wrapper. DO NOT USE ssl:// or tls://. Anything other than tcp:// will not work correctly AS A SERVER, those transports are what you use when making connections with PHP as a client.

Remember that the encryption does not start until after an SSL handshake completes, so the server has to listen in non-encrypted mode for new connections, and encryption doesn't start until certs are exchanged and a cipher is selected. When a new connection arrives you accept it with stream_socket_accept() and then use stream_socket_enable_crypto() to start the SSL session.

3) Keep in mind that the SSL handshake takes time, and that the stream_socket wrappers are high level and not as responsive as the socket extension due to the additional overhead they incur. For this reason you will need to enable blocking for accepting new connections.

newConnStream = stream_socket_accept(ServerListenStream); stream_socket_enable_crypto(newConnStream, true, STREAM_CRYPTO_METHOD_SSLv23_SERVER); Note that this is mainly for HTTP. If you are trying to do something like SMTP then your script will have to react to the "starttls" command, but it would be similar to the above except that you would wait for the "starttls" command before invoking the stream_socket_enable_crypto() function on the client's stream. TLS 1.0 is generally the way to go, SSLv3 is insecure and SSLv2 is buggy. If you use the mozilla recommend cipher list in your context, you'll be fine.
arthurkushman commented 3 years ago

Release for SSL on server side - https://github.com/arthurkushman/php-wss/releases/tag/1.6.3

saschi123 commented 3 years ago

Nice update :) Thanks.