Giter Club home page Giter Club logo

Comments (62)

Shyru avatar Shyru commented on May 17, 2024

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?

from reactphp.

igorw avatar igorw commented on May 17, 2024

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

from reactphp.

cboden avatar cboden commented on May 17, 2024

+1

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

from reactphp.

Shyru avatar Shyru commented on May 17, 2024

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?

from reactphp.

cboden avatar cboden commented on May 17, 2024

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.

from reactphp.

Shyru avatar Shyru commented on May 17, 2024

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...

from reactphp.

igorw avatar igorw commented on May 17, 2024

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.

from reactphp.

cboden avatar cboden commented on May 17, 2024

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.

from reactphp.

Shyru avatar Shyru commented on May 17, 2024

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.

from reactphp.

igorw avatar igorw commented on May 17, 2024

Have you tried the STREAM_CLIENT_ASYNC_CONNECT for stream_socket_client?

from reactphp.

cboden avatar cboden commented on May 17, 2024

@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.

from reactphp.

e000 avatar e000 commented on May 17, 2024

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

from reactphp.

snorkeyg avatar snorkeyg commented on May 17, 2024

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

from reactphp.

cboden avatar cboden commented on May 17, 2024

@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).

from reactphp.

Shyru avatar Shyru commented on May 17, 2024

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...

from reactphp.

superjimpupcake avatar superjimpupcake commented on May 17, 2024

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

from reactphp.

cboden avatar cboden commented on May 17, 2024

@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.

from reactphp.

snorkeyg avatar snorkeyg commented on May 17, 2024

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.

from reactphp.

cboden avatar cboden commented on May 17, 2024

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.

from reactphp.

superjimpupcake avatar superjimpupcake commented on May 17, 2024

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.

from reactphp.

snorkeyg avatar snorkeyg commented on May 17, 2024

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.

from reactphp.

superjimpupcake avatar superjimpupcake commented on May 17, 2024

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.

from reactphp.

cboden avatar cboden commented on May 17, 2024

@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.

from reactphp.

e000 avatar e000 commented on May 17, 2024

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.

from reactphp.

superjimpupcake avatar superjimpupcake commented on May 17, 2024

@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.

from reactphp.

igorw avatar igorw commented on May 17, 2024

We can also implement TLS in userland PHP code.

from reactphp.

MarkoTukiainen avatar MarkoTukiainen commented on May 17, 2024

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

from reactphp.

igorw avatar igorw commented on May 17, 2024

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

from reactphp.

igorw avatar igorw commented on May 17, 2024

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.

from reactphp.

e000 avatar e000 commented on May 17, 2024

According to the comments,

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

from reactphp.

cboden avatar cboden commented on May 17, 2024

From the docs:

Returns TRUE on success, FALSE if negotiation has failed or 0 if there isn't enough data and you should try again (only for non-blocking sockets)

In theory after the initial connection is established we don't emit open(), we call stream_socket_enable_crypto and build the SSL handshake until TRUE or FALSE are returned. If TRUE we emit open() to the application.

from reactphp.

e000 avatar e000 commented on May 17, 2024

Does it actually consume the data in the buffer though, or will the call
to stream_select() always instantly return until there's enough data.
Should test O:

On 12/14/2012 12:16 AM, Chris Boden wrote:

From the docs:

Returns TRUE on success, FALSE if negotiation has failed or 0 if
there isn't enough data and you should try again (only for
non-blocking sockets)

In theory after the initial connection is established we don't emit
open(), we call stream_socket_enable_crypto and build the SSL handshake
until TRUE or FALSE are returned. If TRUE we emit open() to the application.


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

from reactphp.

e000 avatar e000 commented on May 17, 2024

It seems that stream_socket_enable_crypto still blocks with a
nonblocking stream. :\

from reactphp.

igorw avatar igorw commented on May 17, 2024

Huh? Do you have a reproduce case or so?

from reactphp.

DaveRandom avatar DaveRandom commented on May 17, 2024

@e000 I can tell you with absolute certainty that it doesn't. You just need to keep looping over it until it returns either TRUE or FALSE.

Basically it's something like:

while (0 === $result = stream_socket_enable_crypto($stream, TRUE, STREAM_CRYPTO_METHOD_TLS_SERVER)) {
  // do stuff while you're waiting
}

if ($result) {
  // success
} else {
  // fail
}

...obviously the React code would look nothing like that, but I hope that demonstrates the logic you would use.

from reactphp.

igorw avatar igorw commented on May 17, 2024

Yes, we are currently using this in the HttpClient, it adds a retry listener that is run whenever the stream is notified readable.

from reactphp.

e000 avatar e000 commented on May 17, 2024

I wrote some dirty code to test, but you can clearly see that stream_socket_enable_crypto does indeed block

e@e-desktop ~> sudo tc qdisc add dev eth1 root netem delay 300ms 500ms
e@e-desktop ~> php test_ssl.php 
Iteration... 1
Activating ssl...
took 0.883464813232 usecs
bool(true)
Connected!
Wrote 138 
... snip

http://bin.edrama.us/wTxVf-tO3TpiW4i the script in question.

e@e-desktop ~> php --version
PHP 5.3.2-1ubuntu4.18 with Suhosin-Patch (cli) (built: Sep 12 2012 19:33:42) 
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
    with the ionCube PHP Loader v4.0.5, Copyright (c) 2002-2011, by ionCube Ltd.

It's probably worth mentioning that the "usecs" is just a silly typo. It actually blocks for 0.883 seconds.

from reactphp.

DaveRandom avatar DaveRandom commented on May 17, 2024

@e000 Really? I beg to differ...

Iteration... 1
Activating ssl...
took 0.00042986869812012 secs
int(0)
Not enough data, try agian...
Iteration... 1
Activating ssl...
took 1.215934753418E-5 secs
int(0)
Not enough data, try agian...
Iteration... 1
Activating ssl...
took 8.8214874267578E-6 secs
int(0)
Not enough data, try agian...
Iteration... 1
// ...and on it goes

The only changes I made were to get rid of a couple of strict standards errors and stop the retrieved content from being echoed, it was making the output harder to read. Something's odd about the iteration counter as well but a fix for this was not required to demonstrate the point.

Incidentally, do you think maybe you should stop writing for PHP4 compat?

:-P

from reactphp.

e000 avatar e000 commented on May 17, 2024

Interesting. I wonder if it's a bug with PHP then. Or possibly tc?

from reactphp.

DaveRandom avatar DaveRandom commented on May 17, 2024

@e000 I really don't know, I revisited this earlier on today in a couple of environments and I could find no way to reproduce the behaviour you see. While none of the changes I made to your script should affect this element of the behaviour, I did make a few changes, mostly cosmetic and making it E_STRICT friendly because I had error reporting cranked up to max and it was making the output hard to read - but could you try running the version of the script on the codepad in your environment and see if it makes any difference?

If there is some factor that causes it to block, it would be good to track it down and see if it is detectable or can be worked around before this functionality was added to the project. Either the modified script will now work in your env and we can look at the diff, or it won't and it's something about your env.

I find it hard to believe netem would affect the behaviour of non-blocking sockets, but then again I could be wrong - if that is the cause, the same effect would presumably be visible on regular non-blocking socket ops as well (without messing about with crypto)? After all, crypto is basically just applying a filter at the PHP level, it's at a higher level than regular socket ops, not lower.

Still, speculation is useless - can you run a few more tests, use the modified script, remove netem, generally have a fiddle and report back? I know I'm a newcomer to this thread/project but you've sparked my interest now...

from reactphp.

e000 avatar e000 commented on May 17, 2024

@DaveRandom sill blocks for 100ms with netem off.

e@e-desktop ~/c/build> php test_php2.php 
<pre>0Iteration... 1
Activating ssl...
took 0.119113206863 secs
bool(true)
Connected!
Wrote 138 
Iteration... 1
Iteration... 0
Iteration... 1
Iteration... 1
Iteration... 1
Iteration... 1
Iteration... 1
Iteration... 1
Iteration... 1
Iteration... 1
Iteration... 1
Iteration... 1
Iteration... 1
Iteration... 1
Iteration... 1
Iteration... 1
RIP

from reactphp.

e000 avatar e000 commented on May 17, 2024

My libssl-dev is 0.9.8k-7ubuntu8.13.

from reactphp.

DaveRandom avatar DaveRandom commented on May 17, 2024

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

from reactphp.

CMCDragonkai avatar CMCDragonkai commented on May 17, 2024

Implementing this would open possibilities for financial transactions!

from reactphp.

leftdevel avatar leftdevel commented on May 17, 2024

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 :)

from reactphp.

igorw avatar igorw commented on May 17, 2024

@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.

from reactphp.

joshwegener avatar joshwegener commented on May 17, 2024

Is there any update on when SSL will be supported?

from reactphp.

cboden avatar cboden commented on May 17, 2024

@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.

from reactphp.

joshwegener avatar joshwegener commented on May 17, 2024

@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?

from reactphp.

igorw avatar igorw commented on May 17, 2024

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

from reactphp.

heruan avatar heruan commented on May 17, 2024

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?

from reactphp.

cboden avatar cboden commented on May 17, 2024

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.

from reactphp.

attozk avatar attozk commented on May 17, 2024

@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

from reactphp.

vinodkumar4a5 avatar vinodkumar4a5 commented on May 17, 2024

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.

from reactphp.

Shyru avatar Shyru commented on May 17, 2024

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

from reactphp.

bashilbers avatar bashilbers commented on May 17, 2024

Is SSL support still on the roadmap?

from reactphp.

cboden avatar cboden commented on May 17, 2024

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

from reactphp.

vinodkumar4a5 avatar vinodkumar4a5 commented on May 17, 2024

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.

from reactphp.

Venzon avatar Venzon commented on May 17, 2024

any progress with ssl suport?

from reactphp.

vinodkumar4a5 avatar vinodkumar4a5 commented on May 17, 2024

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 [email protected] wrote:

any progress with ssl suport?


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

from reactphp.

tomhatzer avatar tomhatzer commented on May 17, 2024

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

from reactphp.

clue avatar clue commented on May 17, 2024

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.

from reactphp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.