TigerVNC / tigervnc

High performance, multi-platform VNC client and server
https://tigervnc.org
GNU General Public License v2.0
5.24k stars 954 forks source link

Complete VNC over SSH proposal #250

Open hifi opened 8 years ago

hifi commented 8 years ago

The UNIX socket issue became a playground for my VNC over SSH design so I've moved the discussion to its own issue. This also contains a more complete design.

Running applications and full X sessions remotely on a headless system that has Xvnc installed is somewhat complex and insecure usually glued together with port forwarding to localhost. VNC over SSH solved this problem by using the exec channel of SSH as a secure transport of VNC data.

This design relies on client implementation in vncviewer with libssh2 that can execute the helper program on the server to do some proxying for it. The server side helper can do the following things:

All of the options can be done by passing different kinds of parameters from viewer when the helper is executed remotely.

The first option to run xinit session (persistently or closing on disconnect) is the one that I personally like to use on a server if I want to run some GUI utilities on it. For example I could launch the default GNOME session on EL7 remotely without running an insecure VNC TCP server on localhost exposing it to other users.

The second option of connecting to a local TCP socket solves the port forwarding hack you need to do with SSH. It helps secure the session on your local system as you then don't have a loopback TCP socket listening for connections.

The third option of using it to proxy to another host on the same network could also be handy. You could have a single entry point to an internal network where you might run VNC servers on TCP ports and you would avoid the extra setup of having to configure port forwarding for each and every host you could connect to - just install the friendly VNC helper on the entry server or use netcat as the helper directly by executing it instead.

There are endless possibilities you could hack together with stdio over SSH. Netcat is one extra option while the helper application solves local sessions.

So what needs to be done?

  1. Add SSH2 exec support to clients
  2. Create the helper application in a way that it can be accepted into TigerVNC
  3. Optionally add UNIX socket support for Xvnc to allow connection sharing in xinit mode

SSH2 exec support is rather simple but requires a good and flexible GUI to configure properly. It also needs a better way to handle socket I/O and I applaud myself the busy looping hack actually works for demo purposes. It can be tested using netcat on the remote server as said so the helper application is not required just yet.

The remote helper program is another beast and depends on what languages are allowed in the packaged product. Writing it in Perl would be rather easy and it's also readily available on most systems but if all parts of TigerVNC must be native code, it requires quite a lot more work.

Now, can this proposal be either accepted as a whole so I could finish the client side support to produce mergeable pull requests or alternatively have a discussion why this wouldn't work as I've laid it out? Technically it does work as I've written proof-of-concepts for all parts of this chain and with libssh2 there's even native support on Windows to connect.

--- Want to back this issue? **[Post a bounty on it!](https://app.bountysource.com/issues/28923324-complete-vnc-over-ssh-proposal?utm_campaign=plugin&utm_content=tracker%2F3557444&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://app.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F3557444&utm_medium=issues&utm_source=github).
bphinz commented 8 years ago

Speaking off the cuff here, but perhaps this is unnecessarily cumbersome. If you need to have a helper application anyway, it seems like you could have that application do the bulk of the work and minimize the changes necessary to achieve the same result. For example (based on your described use case), a daemon could be written using the LibVncServer API that supports any one of the existing authentication schemes and listens on port 5900. After authenticating, the server would start the proxy or whatever else needs to be started and then send a ClientRedirect message instructing how/where it should reconnect. The ClientRedirect implementation could be changed to support URIs instead of just hostnames (the protocol spec allows for a string hostname, so I don't believe that the protocol itself would need to be changed). ie:

I realize that SSH exec support opens up other possibilities, but at the moment this whole proposal seems very tailored to a specific use case anyway.

hifi commented 8 years ago

Wait, what? You're proposing to replace small changes to viewer (to include SSH transport) with a daemon plus multiple protocol changes?

You now have a daemon listening on a local TCP socket making it require root setup to work overall off the bat. It also requires extra authentication that SSH already did for the user and making actual changes to the protocol itself which are all completely unnecessary for this to work and seems you're thinking of SSH port redirects again which open up local ports as well.

My proposal is very tailored to access a remote headless system, that is true, but it also allows multiple users to do that securely with very minimal changes and not requiring any other authentication than the SSH connection. I don't think "VNC over SSH" has much other practical use than what I intend to do with it anyway.

Have you read the patches or tried? The vncviewer bit even handles user/pass authentication over libssh even though it ignores the host key. Ignoring the quality of them, it doesn't take many lines to make the exec chain work without opening any TCP sockets that could be exposed to remote or local vulnerabilities.

bphinz commented 8 years ago

On Mon, Dec 7, 2015 at 3:20 PM, Toni Spets notifications@github.com wrote:

Wait, what? You're proposing to replace small changes to viewer (to include SSH transport) with a daemon plus multiple protocol changes?

No, I'm not proposing anything. I'm suggesting that introducing a complete external application into the mix (vncpipe.pl), plus code changes may not be the easiest way to accomplish what you want, and presenting an example scenario that would require far fewer changes (sorry, I disagree that adding four new classes to the Java viewer constitutes a "small" change..). If you read my message you would have seen the part where I said "no protocol changes". Where are you getting "multiple protocol changes" from?

You now have a daemon listening on a local TCP socket making it require root setup to work overall off the bat. It also requires extra authentication that SSH already did for the user and making actual changes to the protocol itself which are all completely unnecessary for this to work and seems you're thinking of SSH port redirects again which open up local ports as well.

And you have have external application! Again, I don't know where you are getting this notion of protocol changes (I said an implementation change), or the idea of SSH port redirects. I'm talking about the using the ClientRedirect RFB extension that is already registered with IANA. I'll grant you that it does requires the extra authentication step, but I wasn't trying to develop an end to end solution.

And of course I read the patches. TCP sockets aren't the only way to introduce local vulnerabilities...

hifi commented 8 years ago

If you use the Java viewer patch as an example, I did add that it has superfluous stdio piping support which is not required for SSH exec. That's four extra classes that aren't needed and only one that is. I haven't finished anything because it would be more time wasted on a concept that wouldn't be accepted upstream.

Also vncpipe.pl does only a small portion of the things I suggested it would do as it only handles persistent xinit sessions as it stands.

Giving further thought into the 'external application'. It could also have the ability to connect to a running X session and do the slow copy from it. It would provide you with on-demand remote VNC over SSH to an existing session without running anything on the background waiting for you.

I apologize for my aggressive defensive stand. Try not to take it too personally. I'm more used to heated discussions compared to nice ones.

Eldelshell commented 8 years ago

+1

Not having to setup a SSH tunnel would be a huge win.

Onyx47 commented 8 years ago

+1

Setup is a pain currently, this seems like a great addition.

bphinz commented 8 years ago

I agree that an automatic SSH tunnel feature would be very useful, I would just like to see a more streamlined implementation (to be honest, think this ticket could be broken out into three separate enhancement requests, one for each on Toni's bullet points). There is currently an internet draft specification for VNC URI schemes (much more sophisticated than the simple URI prefix notion I brought up), which includes a specification for an "Integrated SSH" security type. I suggest that any implementation attempt to be compatible with the proposed security type, so that we don't end up with another debacle like we have with the VeNCrypt security type and Vino. x11vnc has a mechanism for using SSH exec to run vncserver and then parse the output in order to determine the RFB port to connect to. It looks to me like the authors of the draft specification opted for the same basic approach in their software. I'm not saying that's the best way, just pointing out existing methods.

hifi commented 8 years ago

Using SSH just as an authentication mechanism and then opening up a TCP socket completely eliminates the integrated security and ease of setup of just using SSH as both auth + transport.

To be family friendly, I'll just call that draft dumb because you already have a transport channel and the specification refuses to use it. If you're afraid of compatibility, all VNC clients can be stringed together with netcat and the ssh client to connect to the server end of this setup if they don't have direct support for "TigerVNC over SSH".

I fail to see why you're so hesitant to make TigerVNC zero setup solution for systems that have Xorg and OpenSSH. Everyone hates to configure VNC for Linux/BSD while also opening up a lot of flexibility with the amount of new methods to serve VNC.

Zero setup. You install TigerVNC server on the remote system and suddenly you can seamlessly connect over SSH to your existing Xorg session or start a Xvnc session. No configuring services, no starting up daemons, no configuration files, no need to setup users.

bphinz commented 8 years ago

To be family friendly, I'll just call that draft dumb because you already have a transport channel and the specification refuses to use it. If you're afraid of compatibility, all VNC clients can be stringed together with netcat and the ssh client to connect to the server end of this setup if they don't have direct support for "TigerVNC over SSH".

That's short-sighted. The focus of the draft is on the URI scheme, which has all kinds of useful applications. I agree that the Integerated SSH security type itself seems almost pointless, however it is already registered as a valid type with IANA, so if we're going to implement something let's be proactive about compatibility.

I fail to see why you're so hesitant to make TigerVNC zero setup solution for systems that have Xorg and OpenSSH. Everyone hates to configure VNC for Linux/BSD while also opening up a lot of flexibility with the amount of new methods to serve VNC.

I'm not "hesitant to make TigerVNC a zero setup solution" at all, so stop trying to spin it that way. Over the past 5 years I've invested literally thousands of hours of my personal time, as well as significant financial contributions to the project, so I've damn well earned the right to say let's stop & discuss something before charging headlong into it. You keep bringing helper applications, netcat, etc. into the mix - and that is what I have reservations about. I'm completely onboard the idea of SSH exec spawing Xvnc and then automatically connecting to it via the already existing & authenticated tunnel. Suggesting that we review existing implementations of that exact feature is in neither defiance nor ignorance on my part.

hifi commented 8 years ago

That's short-sighted. The focus of the draft is on the URI scheme, which has all kinds of useful applications.

It's not really incompatible with anything since there are no protocol changes, only transport which can be worked around as I've pointed out. Only way it makes sense is with "None" authentication type anyway because you're already authenticated.

I agree that the Integerated SSH security type itself seems almost pointless, however it is already registered as a valid type with IANA, so if we're going to implement something let's be proactive about compatibility.

Call it TigerVNC-SSH for all I care. If it's - hypothetically - better than anything existing out there, everyone else would follow your lead in the end. I really doubt it wouldn't generate interest when released because it makes VNC on Linux easy which it has never been and always requires some setup. It's also dead easy to implement in other viewers as a compatibility thing.

Over the past 5 years I've invested literally thousands of hours of my personal time, as well as significant financial contributions to the project, so I've damn well earned the right to say let's stop & discuss something before charging headlong into it.

And I'm trying to! The discussion seems to stop whenever I defend it and try to get something out from your side. I'm also trying to contribute my time into mergeable pull requests and there's no point in working towards it until there's an agreement.

I'd rather just drop the whole idea than fork unless that's the only way to make you understand how it works and why it's the best thing for VNC on non-Windows systems.

You keep bringing helper applications, netcat, etc. into the mix - and that is what I have reservations about.

Netcat was just an example of an incompatible and legacy VNC viewer to go around the SSH exec channel. The implementation only needs a server side helper application to do all the things it needs to do depending on what the client requests with exec parameters for the helper.

I still don't believe you understand how it really works on each of the use cases and I seem to be unable to explain it clearly because it seems overly complex to you- even when I have code examples.

I'm completely onboard the idea of SSH exec spawing Xvnc and then automatically connecting to it via the already existing & authenticated tunnel.

Spawning Xvnc is only one of the intended applications and is the easiest to start with since it doesn't need any modifications. x11vnc like attaching to existing Xorg session would be much more useful for a lot more people and it's very doable after the first steps have been taken. Client side only needs an option to select between what mode to exec the helper in.

The point of all this is to make it zero setup for the user and secure at the same time by reusing existing and proven components like OpenSSH and not exposing any VNC components to other users on neither remote or local side with TCP sockets.

Suggesting that we review existing implementations of that exact feature is in neither defiance nor ignorance on my part.

The draft isn't an exact implementation, not even close. It's more of a hack than what I'm suggesting.

CendioOssman commented 8 years ago

This is getting a bit personal so let's back up a few steps here.

First, I think I need a clearer picture of the problem we're trying to solve here. There's a lot of discussion about implementation here so it gets lost a bit. AFAICT your goals are:

  1. Provide an SSH transport as an alternative to the existing TLS one in a more convenient way than the current -via mechanism.
  2. To not have to configure and start an Xvnc server beforehand

Have I understood it somewhat right? :)

As for 1., I personally think that TLS is just as secure as SSH so I don't see it as giving any security benefits. But I can understand that people can prefer to use SSH as a bit of a VPN to funnel everything through. So I'm not opposed to better integration as long as the code is good and it doesn't make a mess of everything else.

I'm a bit more sceptical about 2.. I understand the convenience, but I'm not sure the approach is a good one the way things work these days. With systemd you really need to start user sessions from a service for things to be set up properly. And there are certainly improvements we can make there. But we need to have something that is spawned off from init, rather than an existing user session.

I suppose we might be able to stick vncpipe.pl in some form in contrib, but I don't feel comfortable giving that method an official seal of approval yet.

hildred commented 8 years ago

On Fri, Dec 18, 2015 at 4:22 AM, Pierre Ossman (Work account) < notifications@github.com> wrote:

This is getting a bit personal so let's back up a few steps here.

First, I think I need a clearer picture of the problem we're trying to solve here. There's a lot of discussion about implementation here so it gets lost a bit. AFAICT your goals are:

  1. Provide an SSH transport as an alternative to the existing TLS one in a more convenient way than the current -via mechanism.
  2. To not have to configure and start an Xvnc server beforehand

Have I understood it somewhat right? :)

you missed:

  1. use ssh for authentication without funny hacks
  2. ability to easily use other transports

As for 1., I personally think that TLS is just as secure as SSH so I don't see it as giving any security benefits. But I can understand that people can prefer to use SSH as a bit of a VPN to funnel everything through. So I'm not opposed to better integration as long as the code is good and it doesn't make a mess of everything else.

ok, first of all I am not an expert on crypto, but I am fairly well read. My best understanding is that at the current time there are no significant differences in the security of the two protocols but that there are differences in MACs, key exchange, and cyphers in that some are supported on only one and only a few are supported on both, and that the security of various MACs, key exchanges and cyphers is constantly changing. Therefore the best practice is to be able to rapidly replace the crypto stack as vulnerability information becomes available. If we do as you propose we would have the advantage that any vulnerabilities that are discovered in only one protocol (or implementation thereof) would not be a show stopper, just use the other one. In other words you may consider this a hearty endorsement of this point.

I'm a bit more sceptical about 2.. I understand the convenience, but I'm not sure the approach is a good one the way things work these days. With systemd you really need to start user sessions from a service for things to be set up properly. And there are certainly improvements we can make there. But we need to have something that is spawned off from init, rather than an existing user session.

If you are right about this, all ssh implementations will have issues and this would be a bug in systemd. remember that with ssh you do not need to use a pty (and we would not want to if we are just using it as a 8-bit clean transport) which makes it entirely an issue that the systemd team would be responsible for working out with the openbsd team (and the systemd guy better be nice as the openbsd guys are following the standards). If on the other hand you can start a user session from a daemon started by init as long as there is no existing user session, we just let ssh worry about starting the session.

I suppose we might be able to stick vncpipe.pl in some form in contrib, but I don't feel comfortable giving that method an official seal of approval yet.

— Reply to this email directly or view it on GitHub https://github.com/TigerVNC/tigervnc/issues/250#issuecomment-165752082.

Ben Hildred Automation Support Services 303 815 6721

hifi commented 8 years ago

Have I understood it somewhat right? :)

Portion of it. Xvnc is only a use case I use. x11vnc like attaching to running display would be trivial to do as well which probably is what most people would like to use. vncpipe.pl is a concept, not a full blown solution and it's purpose is to demonstrate the use of SSH exec channel transport.

As I tried to say before, the full solution would allow you to do many different kinds of VNC connections on the remote side using the helper:

These are only examples of what could be done. Not all are necessarily that useful to have in an official server side implementation. Again, netcat can be used on the server for the last two directly as long as you can optionally type your own exec command.

As for 1., I personally think that TLS is just as secure as SSH so I don't see it as giving any security benefits. But I can understand that people can prefer to use SSH as a bit of a VPN to funnel everything through. So I'm not opposed to better integration as long as the code is good and it doesn't make a mess of everything else.

The security point was more about (Open)SSH having a good track record of updating their stuff when possible weaknesses are found and it offloads the whole thing to a trusted third party product. There's nothing wrong with using TLS for other types of VNC connections.

I'm a bit more sceptical about 2.. I understand the convenience, but I'm not sure the approach is a good one the way things work these days. With systemd you really need to start user sessions from a service for things to be set up properly. And there are certainly improvements we can make there. But we need to have something that is spawned off from init, rather than an existing user session.

Systemd is irrelevant. SSH user sessions are the most convenient way to authenticate and execute something as the user on-demand without needing any help from any service or daemon other than sshd.

I suppose we might be able to stick vncpipe.pl in some form in contrib, but I don't feel comfortable giving that method an official seal of approval yet.

Absolutely not. It's a proof-of-concept which I've been trying to say for months. It's also completely useless without client side SSH exec support.

hifi commented 8 years ago

For reference, x11vnc documentation has the -inetd switch described like this:

       -inetd

              Launched  by inetd(8): stdio instead of listening socket.  Note:
              if you are not redirecting stderr to a log file (via shell 2> or
              -o  option)  you  MUST also specify the -q option, otherwise the
              stderr goes to the viewer which will cause it to abort.   Speci‐
              fying  both -inetd and -q and no -o will automatically close the
              stderr.

              If the libvncserver used supports non AF_INET sockets  (the  one
              bundled  in  x11vnc 0.9.13 and later does), then -inetd mode can
              be used for a raw stdio  pipe.  For  example,  using  the  SSVNC
              viewer exec=... mechanism:

              ssvnc  -viewer  exec="ssh -tt -e none user@host \ ´x11vnc -inetd
              -o log.txt -display :0'"

              where the long cmdline has been split.  In the  above  the  only
              TCP  connection is that of the ssh connection.  There is no port
              redirection (-L), etc.; raw stdio is used on both sides  of  the
              ssh.  In some cases the -tt option is not needed.

So this isn't an original idea and it has been floating around before but it hasn't been simplified into a GUI with seamless server side bits. I tried my SSH exec supporting client with x11vnc by running it with the command of x11vnc -inetd -q -display :0 and it worked flawlessly to attach to a remote X11 session.

The example, however, does not have integrated SSH client but relies on stdio plus OpenSSH client. This is where having plain stdio option gives yet more flexibility than just integrated SSH client which is definitely a good idea anyway to make it easier to run.

CendioOssman commented 8 years ago

If you are right about this, all ssh implementations will have issues and this would be a bug in systemd.

sshd is a service and hence it works correctly. As for it being a bug or not, you're going to have to debate that with the systemd and desktop environment folks. The reality is that things start to misbehave if you don't run things in a systemd created user session (in practice that means doing PAM from a service).

In this case Xvnc and the desktop environment will be running in the session created by sshd, so things are fine so far. But disconnecting and leaving Xvnc running leaves thing nment will be running in the session created by sshd, so things are fine so far. But disconnecting and leaving Xvnc running leaves things in a somewhat weird state as sshd will signal (via PAM) to systemd that the session has ended.

klesteb commented 8 years ago

I would like to interject with a comment. I believe there is a misunderstanding on what SSH does and how it is implemented in OpenSSH. First off, I am not an expert, but I have used the facilities and libssh2 enough to get a good understanding.

SSH is an authenticated, encrypted multiplexed, socket layer connection between and a client and a server. All communication is done over channels. There can be more then one channel active. Each channel may be associated with a subsystem. Shell, Exec, SCP and SFTP are implemented as predefined subsystems. Shell, Exec and SCP are implemented internally, while SFTP is an external subsystem. External subsystems communicate with the sshd daemon over STDIN, STDOUT just like with they do with inetd.

Defining an external subsystem with OpenSSH is an entry in the sshd_config file. Since Xvnc has a -inetd switch that allows it to communicate over STDIN and STDOUT. Running Xvnc under the sshd daemon should be no harder then an entry in a config file. Xvnc would then run under the context of the authenticated connection.

The VNC client would have to have the option to use SSH as a connection method and then invoke the Xvnc subsytem. Once invoked, all communication would be over SSH instead of raw sockets.

Doing this would not involve extra programs nor port redirection. The client just needs to be able to select a "SSH" option and the server needs to be able to spawn Xvnc.

Now off to figure out why Xvnc won't run under systemd on REHL7.

tcwalk commented 8 years ago

Perhaps this comment is off topic, but I want to state that as a user, I would love to see ssh support improved, made easier, or at least more thoroughly documented. I have 2 CentOS servers (development and production) that I connect and access in Windows with SSH, Putty and TigerVNC. A GUI is important for me to view web pages on localhost prior to release. I am also interested in using ssh security with encryption and keys. Plus, other functionality, such as connecting to existing sessions would be great, though I do not understand the requirements and compatibility issues.

Putting VNC and SSH together takes a lot of time. For example, I came here looking for more info on the -localhost option. Without it, I can connect through SSH port forwarding. With it, I have not yet figured it out. It would be nice to have -localhost and require SSH tunneling.

As for documentation, vncserver@:.service states that for more info on -via to man vncviewer, while this man doesn't exist on my CentOS installation. Plus, man Xvnc says to see the web site (only tigervnc.org in the man) for more info for -localhost and ssh. I tried and hit the wiki link. That is how I got here.

Sorry to complain. VNC is a great tool that can be improved. I do not have the time to become a project developer. If it might help and I can retrace my steps, I can contribute instructions.

hildred commented 8 years ago

@tcwalk, in the example you quoted, n and m need to be replaced with digits.

tcwalk commented 8 years ago

@hildred Thanks. My mistake was not realizing that in ssh -L the first host argument is optional. I deleted the sentence in an edit. My other thoughts remain, including that I can port forward without -localhost, but not with it. I have tried in CentOS and Windows. It is probably a simple user error, but it is difficult to find documentation.

tcwalk commented 8 years ago

Sorry to sidetrack this, but I did figure it out. As usual, I exhausted all alternatives before stumbling into the correct way. My issue was with ssh -v -C -L 590N:localhost:590M hostB which in Putty results in Local port 590N forwarding to localhost:590M I was thinking that localhost referred to my workstation and tried every conceivable combination with the host ip before concluding that localhost is on the host. To me, it looks like running ssh -L localhost:590N:localhost:590M hostB makes all of the tunneling on the client. But, that apparently isn't the case.

So, I have a slightly better understanding of what is happening and can now run -localhost and -nolisten tcp. It seems that many online tutorials don't really understand either. Therefore, I hope that my comments are relevant in that I provide evidence that incorporating ssh more natively into vnc would be good.

Rufflewind commented 8 years ago

@tcwalk The full syntax for a local (-L) port forwarding is like this:

ssh -L <bind-host>:<bind-port>:<dest-host>:<dest-port> <host>

To elaborate, <host> is the SSH server. This usually coincides with your VNC server, but it need not be so. For example, in a more complicated situation, your SSH server might be just a firewall/gateway server, with the VNC hidden behind the wall and not directly accessible from the outside world.

<dest-host> and <dest-port> describe how the VNC server is to be accessed, from the perspective of the SSH server.

<bind-host> and <bind-port> describe where the listening port of the tunnel, from the perspective of the SSH client. By default, if <bind-host>: is omitted entirely (along with the colon), it usually binds to just localhost.

In your example ssh -L localhost:590N:localhost:590M hostB, you have constructed a tunnel that listens on port 590N on the loopback interface of your client and forwards connections to port 590M on the loopback interface of hostB. This means your VNC server should be running on hostB and listening to port 590M of the loopback interface (localhost). Your VNC client should be trying to connect to localhost:590N on the same host as that of the SSH client.

        [client host]                                               [hostB]
VNC client >--> localhost:590N >---------- SSH ----------> localhost:590M >--> VNC server
DaburLal commented 6 years ago

I have been encountering similar problems. After the Secure shell is set and the tunnel is established between server and client , i open my VNC server and try to connect to VNC server with localhost:5900 . It connects but the VNC session does not go through the tunnel although using netstat -aon | find ":5900" shows that the tunnel is established.

On my VNC server it says Got connection from client 127.0.0.1. Is this correct or shall it give the ip address of client ?

Waiting for your valuable inputs. Thanks!