Thursday, August 1, 2013

Safe, Secure, Portable Remote X-Windows in the Browser

It is indeed possible to be sitting at some remote location such as a hotel, coffeeshop, store, library or bus with only public, unencrypted internet wifi access and a low-powered windows netbook and still securely access a complete X-Windows desktop over the internet.

OK, this scenario is not quite as fast as being on the physical X-windows machine, especially when you fire up a web browser with a bunch of graphics, but it can be just as good as being there for almost everything else. If you think about it, this is just the kind thing X-Windows was originally designed for: remote access to a graphical desktop on a display server via a dumb terminal. It's really no different over the internet. These dumb terminals in the old days used to be implemented as hardware, but effectively any dumb Windows netbook can play that role.

Given you have access to a running Unix machine at home or work, even one without a monitor (known as a "headless" display) all you need are a couple pieces of software on the Windows laptop: Chrome and Putty, and a bit of configuration magic running on the Unix machine you are accessing.

This setup strategy gives you X-windows in your web browser via a free VNC Chrome plugin, tunneled through an SSH forwarded connection to a headless server behind a firewall running a VNC client, connected to X-windows running in a Virtual FrameBuffer server. There are a few bones to connect, and I will try to explain this.


The Virtual Frame Buffer server (Xvfb) is something that comes with the X-windows distribution in the form of a kind of virtual video driver component. It is similar to the mechanism used to serve up Windows Remote Desktop, in that it uses some code to read the Frame buffer that stores the Windwos Image, but it's Unix instead of Microsoft Windows. Basically the deal with Xvfb is that it's treated just another type of video card driver, like Nvidia or AMD. But instead of displaying to a video card, it "displays" everything live, to a space in memory. Additionally, no monitor or keyboard has to be connected. it's all redirected to run as a complete desktop in memory, as if it were connected to a real mouse, keyboard, video card and monitor. When you run X using this driver, it just sort of sits there in no man's land, running X-Windows as if it were running on the local machine.

To access the machine running the VNC server behind the firewall, you must first have SSH access to a Unix machine in the DMZ in front of the firewall. There are three options from here.

1. Setup the VNC server on the DMZ machine. This is probably a terrible choice, as it exposes both X Windows and VNC connections to the open world. Technically, it can be done but addresses should be bound to non-public IP address segments (e.g 192.168.X.X or 10.0.0.X) on your internal network. I would not trust this kind of setup, and thus won't go into it.

2. Setup VNC on a separate machine that can only be accessed on the internal network. This is a fine solution, but requires another machine, which in my mind is a waste and excessive. But a good choice if you have tons of computers to dedicate to tasks like this.

3. Setup VNC in a jail whose interface can only be accessed over private address space behind the firewall. This is the ideal and most economical solution, and can easily be done on FreeBSD. If you are smart, you will be using this operating system in your DMZ. (If you are very smart you would be probably be using OpenBSD for this purpose) In any case, setup a jail on your FreeBSD DMZ machine with a local address (192.168.X.X or the like), install x11/xorg (X-windows) and net/tightvnc net/x11vnc ports. They are a bit of a long build, but worth it.

The idea here is if  X is running inside a FreeBSD jail on the host machine placed in the DMZ, and the jail is only accessible to protected network address space (such as 192.168.x.x), only ssh tunneling can expose the machine from the outside. 

NOTE: After upgrading and preparing a plain old jail to test this out, I am backing off my recommendation to use the tightvnc port until I can manage a working configuration with it. Tightvnc worked in a non-jail environment, and has a few problems that I don't understand yet, so I've modified the instructions to work with the net/x11vnc port. I'll try to provide the net/tightvnc configuration sooner or later, because I do believe the performance is rated better. However, the net/x11vnc port does work inside a jail with some adjustments. I've highlighted the changes and additions I made to orange.

Once you've built a jail according to the manpage for jail(8), You'll probably want to start it with a command like this:


> jail -c -f simple_jail_config

where simple_jail_config is a file that looks something like this:

testjail {
path=/usr/home/username/192.168.0.49;
mount.devfs;
allow.raw_sockets;
allow.sysvipc;
host.hostname = testhostname;
ip4.addr = 192.168.0.49;
interface = rl0;
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
}

That's the first part of the setup. It can be done on a headless UNIX server. What follows is a set of commands to fire up the server-side programs. (The following was a setup modified from technique shown at http://en.wikipedia.org/wiki/Xvfb). 

On your VNC host (be it a jail or otherwise) type, as a non-root user:

> export DISPLAY=:1
> Xvfb :1 -screen 0 1024x768x16 &
> fluxbox -display :1 &

The second part of server setup is running VNC server as a companion process to X. VNC will take whatever desktop you are running (even a virtualized one like Xvfb) and will transmit it over the wire to a VNC client running on another machine. 

> x11vnc -ncache 10 -display :1 -bg -nopw -listen 192.168.0.49 -xkb

That's all you need to do on the server. Three command lines.

Some explanation is due. VNC is run as a co-process to X because of security problems with serving X connections directly over the wire, even when X is protected by SSH forwarding.

One of the things about X (a good thing and a bad thing) is that you can redirect windows and keystrokes to other X servers on other machines. This should never be done in an insecure environment, because it exposes all kinds of details that can compromise your privacy. So you will always want to use SSH to cryptographically secure the connection.

There is a feature in SSH that allows global forwarding of incoming connections. However, on good UNIX distributions like FreeBSD this is turned off by default. Due to security problems that can crop up via the MIT Magic Cookie, complexity of the X protocol, and callbacks to client X connections, you should not use this feature to forward your X-Windows connections directly. Instead, use VNC as a proxy to X, which simplifies the security model greatly. With VNC there is only a single connection for SSH to tunnel, and it doesn't rely on wobbly trickery with SSH and the MIT Magic Cookies and callback connections to the client every time a new application is opened.

For more info, See this excerpt from SSH: Secure Shell Definitive Guide, O'Reilly. It's complicated. http://csce.uark.edu/~kal/info/private/ssh/ch09_03.htm 

Other positive side-effects of pairing an X-windows connection with a VNC proxy is that you get slightly better performance over the wire, and compatibility with just about any client platform. In other words, you don't have to install and run a big, fat X-server on the remote client to get full remotely-served X desktop. Using the VNC scheme, small, low-powered machines like netbooks running Windows or some other OS can access X-Windows as easily as UNIX laptops running X-Windows.

So the strategic bottom line is that you must pair VNC with X-Windows on the server. VNC will tap into the virtual frame buffer of the X server, and act as a kind of proxy between the X server and remote VNC client. Since the protocol is elegant, it can be safely tunneled through SSH, which can port-forward the VNC connection to a local port on the client machine, which is one of the magical, almost quantum features of  SSH - the ability to transport the interface of one machine behind a firewall to the local interface of some other machine in front of a firewall. Finally, the VNC client on the remote machine's web browser has only to connect to one of its own ports to access the whole thing.

As far as the client setup is concerned, it's quite simple. 

First, install the Google Chrome VNC plugin. It's free, from the Chrome web store. 

Secondly, install a copy of Putty, the free and venerable ssh client. If you are running Linux or OS/X on a laptop, you probably already have ssh, so you can dispense with Putty.

For Windows users, Putty should be configured with a profile to access the host UNIX machine .
In other words, in the Configuration menu, in the Session option, give the IP address or hostname of the DMZ host. Port should be already set at 22.


Next, you'll need to scroll-down the configuration tree to the section Connection//SSH//Tunnels and set the source port to something like 3333

Next, set Destination to:

[host]:[port]


Where [host] is the hostname or IP address of the machine behind the DMZ firewall, running the vnc server, and port being the port number that VNC server is attached to. Mine is usually port 5902, but you can find this for your system by getting on the VNC host and looking at the logfile for vncserver after it has been started. It's in the hidden .vnc directory in your home directory. There will be an entry in the logfile saying something like: Listening for VNC connections on TCP port 5902

Once you've entered these two numbers in Putty, click ADD

Then go back to the Session menu selection option and SAVE your profile. From your client laptop when you make a connection to the server using putty, you'll be prompted for your username and password, and dropped into a shell. Leave the Putty session open, because it will make the VNC server connection available to you on localhost port 3333.

At this point, you can open Chrome, open the extension, and type in localhost:3333 to make the connection. You may be asked for a password. That's all there is to it. Your X-Windows desktop should display in a detached window.