Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Socket] SSL support #2

Closed
igorw opened this issue May 10, 2012 · 62 comments
Closed

[Socket] SSL support #2

igorw opened this issue May 10, 2012 · 62 comments

Comments

@igorw
Copy link
Contributor

igorw commented May 10, 2012

Possible by by using a stream context, see comment in: http://php.net/stream_socket_server

@Shyru
Copy link

Shyru commented Jun 15, 2012

I would be willing to implement this feature. We would need this for Websocket (Ratchet) with SSL support.
See here: ratchetphp/Ratchet#33
But I'm not sure on how to implement this properly because SSL may need a lot of options.
Perhaps it would be good to add a method like enableSSL($options) where options is an array of options that are passed to individual stream_context_set_option-calls. This would be really flexible, if listen() is called afterwards it would check if any ssl-options where passed and setup ssl accordingly.
Alternativly we could also just add an $sslOptions parameter to listen() and if it is properly set up enable ssl for the socket.
What would you prefer?

@igorw
Copy link
Contributor Author

igorw commented Jun 15, 2012

That's cool! Having a parameter for listen seems like the best way to go.

@cboden
Copy link
Member

cboden commented Jun 15, 2012

+1

Please type hint the new parameter as an array. The code inside listen should create a context from it.

@Shyru
Copy link

Shyru commented Jun 16, 2012

Ok i started implementing this here:
https://github.com/Shyru/react/tree/ssl-support
However I have problems connecting to my SSL-enabled server. I think it has something to do with StreamSelectLoop. (See last commit message) Care to have a look a it?

@cboden
Copy link
Member

cboden commented Jun 17, 2012

I spent an hour troubleshooting it (without internet :/). I was able to replicate the problem on server.php, but not able to fix the problem in React.

In server.php if you set stream_set_blocking($socket, 0); and run testssl.php you will get the same errors. For testing sake I set all React sockets to blocking and increased the timeouts, but that didn't fix the issue.

I'll try to take a look at it again tomorrow evening if anyone hasn't solved it by then.

@Shyru
Copy link

Shyru commented Jun 18, 2012

Yeah, i also thought it was the blocking mode, so I commented out the appropriate lines, but couldn't get to work it either. I hope I have time at work to have a look at it...

@igorw
Copy link
Contributor Author

igorw commented Jun 18, 2012

The approach that redis is taking would work for me too. They don't support SSL out of the box and advise you to use stunnel instead.

@cboden
Copy link
Member

cboden commented Jun 18, 2012

I admittedly don't know the specifics on how TLS/SSL works. After a bit of reading I think I understand the problem. Given how SSL/TLS works I think socket_select() inside StreamSelectLoop is interrupting the secure handshake.

@Shyru
Copy link

Shyru commented Jun 18, 2012

I also thought about 'socket_select' being the culprit, because its the biggest difference to server.php. Any Idea as to why socket_select is a problem? Any idea for a workaround?

@igorw I think stunnel would be the last option. Allthough I understand the reasoning for redis, I think this is a bit different here. Nobody said "use stunnel" when asked about ssl-support for node or apache, because they are both (as well as react/ratchet) something that directly interfaces with the browser. So having directly integrated ssl-support would be beneficial for wider adoption of react/ratchet. - Just my 2 cents.

@igorw
Copy link
Contributor Author

igorw commented Jun 18, 2012

Have you tried the STREAM_CLIENT_ASYNC_CONNECT for stream_socket_client?

@cboden
Copy link
Member

cboden commented Jun 18, 2012

@Shyru Taking a second look at it, I think the culprit is Server.php. listen calls handleConnection which calls $loop->addReadStream() which calls stream_socket_select() which calls your application when an event comes in. This all seems to be happening before the server and client have agreed on SSL.

Server::handleConnection should not be called before the client and server have negotiated SSL.

I think that will solve one problem, but I imagine that's not the only one. If the server is non-blocking how does the handshake happen after stream_socket_accept is called? I suppose we could set the master socket to block before each accept call and un-block after, but that seems a bit hackey.

@e000
Copy link

e000 commented Jun 22, 2012

@cboden It's extremely hacky, and a maliciously crafted connection could essentially halt the entire reactor.

@snorkeyg
Copy link

Any progress on this? Willing to have a crack just don't want to duplicate effort.

@cboden
Copy link
Member

cboden commented Aug 14, 2012

@snorkeyg I don't think there has been any progress, unfortunately. Contribution is very welcome!

The issue seems to be that PHPs handling of SSL on sockets expects that sockets block, which they don't in React. To implement SSL I think someone would have to write SSL negotiation in PHP (much like how @igorw wrote an async DNS client in React).

@Shyru
Copy link

Shyru commented Aug 14, 2012

I spent a lot of time googling around this issue, but did not find any meaningful. Found a lot of bug reports on php but they all dealt with connecting to ssl servers with async. (This was a known bug some time ago).
I got the impression that nobody ever tried to write an async ssl-enabled socket server in php, and as such it does not work and is probably a bug in php.
The closest thing I found was this from the nanoserv change log:

1.1.0 - 2007/10/26

  • Added non blocking crypto handshake for tls and ssl connections

I even loaded the source code and made a diff between the version's but couldn't find out anything meaningful. I think it also only deals with async connects to ssl enabled servers.
Having found out all this, I kind of gave up. :-(
But I still have great interest in a solution to this!

Perhaps it would also be an idea to crate a bug report on php to see what the developers say...

@superjimpupcake
Copy link

Check out https://github.com/superjimpupcake/Pupcake, it is now supports https server building in PHP, and based on php-uv and stream_socket_server in php

@cboden
Copy link
Member

cboden commented Aug 16, 2012

@superjimpupcake I didn't see anything special in your SSL commit that shows PHP handling SSL asynchronously.

file_put_contents specifically blocks and even though you're setting SSL options with stream_context_set_option we have test cases where, when non-blocking is set, PHP will skip the SSL handshake in attempt to pass-through.

@snorkeyg
Copy link

I have successfully implemented a secure websocket with http://code.google.com/p/phpws/ before. That was awhile ago now though.

Not sure if that may help provide an example of how it can be done? I have implemented stunnel for the moment to secure rachet websocket for the time being.

@cboden
Copy link
Member

cboden commented Aug 18, 2012

Thanks for the link @snorkeyg but that library also blocks. You could turn blocking on in React and easily implement SSL, but that's not ideal.

Blocking I/O will severely limit the number of concurrent connections to the server as well has open it up to DOS issues.

@superjimpupcake
Copy link

Thanks for your feedback cboden,. I think in Pupcake, ssl does get handled asyncronously.

The following code:

file_put_contents($certificate, $cert_content);
stream_context_set_option($context, 'ssl', 'local_cert', $certificate);
stream_context_set_option($context, 'ssl', 'verify_peer', false);
$server = stream_socket_server("$protocol://$ip:$port", $errno, $errstr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN, $context);

only happens once when the server starts ( calls to $app->run()), for all the client sockets, it is handled in the async fashion because:

$loop = uv_default_loop();
$poll = uv_poll_init_socket($loop, $server);
uv_poll_start($poll, \UV::READABLE, function($poll, $stat, $ev, $server) ...

php-uv handled all async operations.

@snorkeyg
Copy link

Sorry @cboden only just saw link to that library on Rachet issue for this. I remember now at the time blocking was an issue because it was for one hardware device to send messages to two browser clients.

@superjimpupcake
Copy link

Just check out phpws, it is using the same technique as Pupcake to handle ssl:

./demo_ssl.php:57: stream_context_set_option($context, 'ssl', 'local_cert', $this->getPEMFilename());
./demo_ssl.php:59: stream_context_set_option($context, 'ssl', 'allow_self_signed', true);
./demo_ssl.php:60: stream_context_set_option($context, 'ssl', 'verify_peer', false);

So I would like to know more details on the potential blocking issues with this technique, if there are any.

@cboden
Copy link
Member

cboden commented Aug 19, 2012

@superjimpupcake Here is the most basic example of an async SSL server in PHP (courtesy of @Shyru): https://gist.github.com/3395757

Run server.php and then run client.php in two CLI environments. You'll notice it works. Then uncomment the stream_set_blocking line to make the server run asynchronously and run the two scripts again. It doesn't work.

PHP sockets are blocking by default. phpws and pupcake don't explicitly set the stream socket server to be non-blocking so SSL works in both of them, but they're both synchronous, which severely limits the server from handling concurrent connections and makes them susceptible to DOS issues.

@e000
Copy link

e000 commented Aug 20, 2012

The only ways to get this done would be to either patch the C part of PHP that handles stream + SSL to work w/ async SSL connections, or write our own wrapper in C to do it ourselves and install it as a PHP Extension.

@superjimpupcake
Copy link

@e000, after a few hours research, i agree with you. I'm trying to see if the author of php-uv extension can help with it.

@igorw
Copy link
Contributor Author

igorw commented Aug 20, 2012

We can also implement TLS in userland PHP code.

@MarkoTukiainen
Copy link

Hi! Has there been any development on this feature, or was it abandoned due to the issues with PHP?

@igorw
Copy link
Contributor Author

igorw commented Sep 3, 2012

It's quite hard to do this. Seems to me like we have two options:

  • Patch PHP core to support real async SSL
  • Implement async SSL in userland

@igorw
Copy link
Contributor Author

igorw commented Dec 13, 2012

This should in fact be possible to enable SSL after the connection is done with stream_socket_enable_crypto. Thanks to @DaveRandom for pointing that out.

@e000
Copy link

e000 commented Dec 14, 2012

According to the comments,

stream_socket_enable_crypto is likely to fail/return zero if the socket is in non-blocking mode.

@DaveRandom
Copy link

@e000 Can you check the return value of the stream_set_blocking() call?

@CMCDragonkai
Copy link

Implementing this would open possibilities for financial transactions!

@leftdevel
Copy link

Hi guys. I'm quite interested on this. Any advice if ssl will be supported soon on React/Ratchet? Any workaround in the meanwhile?

UPDATE:
Sorry guys. After reading all your comments I realized that this is more likely a php issue?.
We'll try to use aws elb to get around this :)

@igorw
Copy link
Contributor Author

igorw commented Jan 28, 2013

@oscarballadares There is a WIP pull request at #119. If you want to help out, you can look at the TODOs and send a PR to the ssl branch.

As for workarounds, as mentioned previously in the comments, you can use stunnel.

igorw pushed a commit that referenced this issue Apr 13, 2013
Unref timer when cancelling it
@joshwegener
Copy link

Is there any update on when SSL will be supported?

@cboden
Copy link
Member

cboden commented May 31, 2013

@joshwegener Neither @igorw or myself plan to implement SSL in React. If someone else is willing to finish #119 we'll accept the PR. Due to the performance cost of doing SSL in user-land code we recommend having a separate process (Nginx/STunnel) handle SSL.

@joshwegener
Copy link

@cboden Just took a quick look at both, they appear to be for windows? What do you recommend for Linux (as Server)? And could you point me in the direction of a good tutorial?

@igorw
Copy link
Contributor Author

igorw commented May 31, 2013

@joshwegener not sure what makes you think that. nginx and stunnel are not windows-only.

@cboden cboden mentioned this issue Dec 10, 2013
@cboden cboden added the wontfix label Feb 16, 2014
@heruan
Copy link

heruan commented Apr 2, 2014

Unfortunately using an SSL wrapper such as nginx/stunnel will break Connection::getRemoteAddress() (which will always return 127.0.0.1) and client certificate info retrieval, e.g.

$context = stream_context_get_params($stream);
var_dump($context["options"]["ssl"]["peer_certificate"]);

Any chance to have real SSL support on the roadmap again?

@cboden
Copy link
Member

cboden commented Apr 3, 2014

I'd be willing to accept SSL in if someone were to finish PR #119 but it's not work that I intend on doing anytime soon (if at all).

In my projects I use a reverse proxy which will usually set the actual remote address as meta data in the stream. For example if you're using HTTP there will usually be a X-Forwarded-For header with the correct value.

@attozk
Copy link

attozk commented Apr 29, 2014

@e000 & @DaveRandom

FWIW The issue with stream_socket_enable_crypto() blocking has been resolved in Version 5.3.3 (and newer). See https://bugs.php.net/bug.php?id=45808 & http://php.net/ChangeLog-5.php

@vinodkumar4a5
Copy link

Hi,
I need a client which can communicate with the server using socket.io+ssl connection in c++. I got some codes in java but i want in c++.if it is a wesocketclient+ssl(wss) is also fine for me. can any body share the code or information with me please..

Thanks,
vvk.

@Shyru
Copy link

Shyru commented Jun 15, 2014

Since 5.3 Qt (C++ Library) has a Websocket implementation (Client and Server) that also supports SSL.
See here: http://qt-project.org/doc/qt-5/qtwebsockets-index.html

@bashilbers
Copy link

Is SSL support still on the roadmap?

@cboden
Copy link
Member

cboden commented Sep 8, 2014

With the SSL changes in 5.6 this is something I'm going to re-evaluate. If an SSL socket server is implemented it will require PHP >= 5.6.1

@vinodkumar4a5
Copy link

With out any library support also we can do. The only thing is you need to be create secure channel using HTTP CONNECT method. After the channel has established you need to send websocket upgrade request to server through that channel.

@Venzon
Copy link

Venzon commented Nov 24, 2014

any progress with ssl suport?

@vinodkumar4a5
Copy link

Hi Luke,
Actually i don't need exactly SSL support. my problem was that
client was unable to communicate to the server in the proxy environment. So
for that i ran the server in 443 port(all other ports were blocked in
proxy), I authenticate the proxy inside my client after that it started
working. So for me no need to implement pure SSL/TLS. So solved my problem
in the above manner.

Thanks,
Vinod Kumar.

On Tue, Nov 25, 2014 at 1:14 AM, Luke notifications@github.com wrote:

any progress with ssl suport?


Reply to this email directly or view it on GitHub
#2 (comment).

@tomhatzer
Copy link

Hi everybody!
Any news on this? :)
Thanks!
Tom

@clue
Copy link
Member

clue commented Sep 19, 2015

Thanks for the elaborate discussion so far! 👍

This is kind of an old issue and things have changed quite a bit since then :-)

React now consists of individual components that are maintained individually. Supporting SSL/TLS is related to two components:

As such, I've just filed a new ticket reactphp/socket#24 to keep track of this, so I suppose it makes sense to focus our SSL/TLS related efforts on this component.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests