I write this sitting at Maude's Cafe in downtown Gainesville via
GRU's public wireless network which was
just deployed. I'm doing it, coincidently enough, over VNC encrypted via SSH. This ties in nicely with
my recent wireless articles, including my
initial adoption and
So, while I suck down a nice root beer float and listen to some excellent Jazz, won't you join me as I discuss configuring VNC to be secure via OpenSSH, using some port forward magic, encryption, and an optional lite install of OpenSSH on Windows NT/2K/XP courtesy of Cygwin and Network Simplicity. (This works end to end doing Linux to Linux straight up as well, but I am on my W2K laptop right now.)
Additionally, I'm going to briefly mention configuring Keychain under Debian. It's discussed at length by it's author in a IBM developerWorks article. Keychain is a very slick way of maintaining RSA key passphrases in memory safely without having to type them in all the time. You can stick it in your .bash_profile or .xsession, enter the phrases once, then you're good to go. (Just lock your desktop or logout before you get up.)
Configuration Summary Steps
First, I'm going to walk through installation of the Windows NT based OpenSSH daemon, which works basically like it does under Unix, but it's been ported to work properly under Windows. If you're doing Unix to Unix VNC tunneling with SSH, you can skip this item and the next one, since your SSH is good to go.
Next, I'm going to discuss getting the Windows VNC client ready to go. There are a few things we need to do prior to using it, especially on low bandwidth links.
Then, I'll walk through SSH port fowards, compression, and encryption options. This is the most important section and will cover the two most popular ways of securing a VNC session to some other machine directly or via a SSH daemon operating as a proxy.
Next, I'll quickly write about PuTTY, an SSH terminal client for Windows with port forwarding capabilities.
Finally, I'll discussion a simple Keychain configuration.
OpenSSH on Windows NT/2K/XP with Cygwin
First, you need to install a copy of Network Simplicity's
OpenSSH on Windows
for NT based
Windows systems. Fetch the latest version there, then run the included Setup.exe
file. If you already have a Cygwin environment on the
box in question, stop the installation and obtain and install
OpenSSH for Cygwin.
OpenSSH on Windows is designed for boxes with no prior Cygwin environment as explained
by the author in a
to the support forum.
Once installed, the README outlines a few steps you have to take to get your version
of OpenSSH ready to roll. By default, everything is installed under
C:\Program Files\NetworkSimplicity where familar Unix conventions should jump out at
you. You'll need to create a etc/passwd file with mkpasswd and a etc/group
file with mkgroup as outlined in the README. Thereafter, net start opensshd
should start OpenSSH. The Quick Start file was all I needed to get up and running.
For compression, I edited C:\.ssh (there's a period in there) and added
a file named config with
(This may be undesirable if you plan on using TightVNC, which can do its own zlib compression;
Next, we'll get VNC Viewer ready to go.
Getting and Preparing VNC Viewer
You probably already have VNC Viewer for your platform, but if not, you can get it
from VNC's new home, by the original creators of VNC, at their
For Windows, you'll need to allow the viewer to make connections to the localhost. This
is disabled by default and no configuration option exists to enable this. So, you will need
to edit the registry to enable this feature. The option is called AllowLoopback
and exists under the HKEY_LOCAL_MACHINE\Software\ORL\WinVNC3 path.
At least on my machine, the ORL\WinVNC3 portion of the path did not yet exist.
You can create the key manually and then add 1 as a hexadecimal base, or copy
the entry below into a file with a .reg extension and double click it.
(You shouldn't need to restart.)
Another potentially useful, but not required option is to enable LoopbackOnly which
prevents VNC Viewer from making non local connections. Useful if you don't want to accidently
make an insecure connection. (Which could be disasterous.)
For local connections, VNC Viewer might want to use Raw encoding. Don't let it. The best
choice is still Hextile encoding. Next, if you don't want to mess with your X colour depth
and restart X, you can enable Restrict pixels to 8-bit as well for a speed increase on slow links.
If usability on a slow link is desirably, then fetch a copy of
TightVNC viewer. It's a drop in
replacement for VNC Viewer on the client side, and everything above applies, but you need
the TighVNC server as well, or something that supports TightVNC compression options.
supports TightVNC, and servers like
KDE's Krfb support TightVNC
Encrypted Tunneling with OpenSSH
Now, it's time for the fun part. Herein, we will summon the power of OpenSSH local port fowarding.
Before getting into command line semantics, let me explain plainly how local port fowarding works.
With local port fowarding, you tell your local OpenSSH client to listen on a dummy port of
your choice (which usually has logical reasoning behind it). You also tell OpenSSH that you would
like to relay traffic from this dummy port to some other machine on another (or same) port.
Naturally, an OpenSSH daemon running on the machine you wish to relay the traffic to (or through)
is the destination, and it will be the machine you actually perform a Secure Shell login to during
this operation. (You can request that no command prompt be available and that no tty get allocated;
after all, you are tunneling.)
For example, here we wish to securely tunnel VNC traffic from a local machine, 188.8.131.52,
to some other machine
running a VNC server. The VNC server is running on port 5900 on machine 192.168.1.55. The
remote OpenSSH server will be on 192.168.1.55. We use OpenSSH to locally listen on port
5901 on 184.108.40.206 and tell it we want the traffic forwarded to 192.168.1.55 on port 5900 and that
we wish to use the OpenSSH daemon on 192.168.1.55 as our relay. This is one possible way
of locally forwarding traffic and the corresponding ssh command arguments are:
ssh -L 5901:192.168.1.55:5900 email@example.com
The command may be unclear at first glance, it was for me. The kicker is the middle argument
in the colon seperated list to -L. The first item is our local port, 5901, the last is the
remote port we wish to foward traffic on local port 5901 to. So what's the middle arugment?
It's the machine we wish to actually foward the traffic to with respect to the OpenSSH
server we are connecting to. In this instance it is 192.168.1.55.
As you will recall in this example, 192.168.1.55 is running the VNC server we wish to relay traffic
to, so this important detail may be lost. Another example.
Let us imagine, instead, that we want to foward traffic again from port 5901 on the local machine,
220.127.116.11, but this time we're on a dial up connection outside our "internal network" and wish to
access port 5900 on firewalled machine 192.168.1.55. How can we do that? Well, we can't without
a little help from OpenSSH, as the address is nonroutable and we can't, securely, access it directly.
(Assuming VNC traffic is firewalled off.) So, we must instead relay the traffic through our "internal network's"
firewall machine, 192.168.1.1. It is the OpenSSH daemon on that machine that will then relay our
traffic from 18.104.22.168 to 192.168.1.55 by sending our traffic on port 5900, from 192.168.1.1,
to 192.168.1.55. From the perspective of 192.168.1.55 running the
VNC server, the connection request actually came from 192.168.1.1. This additional machine, the
firewall, changes our SSH arguments slightly.
ssh -L 5901:192.168.1.55:5900 firstname.lastname@example.org
As you can see, the middle argument to -L is with respect to how the "internal network"
is configured, and need not even be access from the outside world (and it's not), since
the OpenSSH daemon we're connecting to is on the firewall as indicated in the last portion of
the command argument.
In this instance all we're interested in is local port fowarding, so we can disable the execution
of a command shell and the allocation of a tty. For that, we use -T to disable pseudo-tty allocation
and -N so you do not get a shell and cannot execute commands. If your firewall is an
older box with a slow CPU, like mine (P133), you could benefit from utilizing the -c option
and choosing the blowfish cypher. It's considered to be quite secure, and is less
CPU intensive than using 3DES, the default. But I leave that choice to you. Thus, our final
ssh command for a tunnel with encryption through a firewall would be (backslash continues
the command on the next line as 'one line'):
ssh -L 5901:192.168.1.55:5900 -N -T -c blowfish \
I find that works quite nicely for my wireless VNC sessions from outside the "internal network".
It's important to note that traffic is unencrypted while it travels from your dummy port
to your local ssh port on your local loopback device.
It's then unencrypted again from your relay machine, if you're using one,
across the "internal network" to the box running a VNC server.
Setting up port forwards with PuTTY
is an excellent Open Source SSH client for Windows which replaced my aging install
of Tera Term Pro with the SSH extensions. One of its unique features (at least for
Open Source Windows SSH clients) is the inclusion of local and remote port forwarding
capabilities. We can use these to accomplish the port fowards we configured above,
but without installing OpenSSH for Windows or playing with any configuration files.
If you don't already have a copy of PuTTY,
download a copy
and rejoice. Once your excitement has calmed a bit, either run the new installation
program or simply copy putty.exe into a directory where you want it to live. Then, run it.
PuTTY comes with an extension set of options that ought to work for even the strangest
configurations, but I'm not going to discuss them here. Instead, turn your attention to the
SSH option in the category tree which should be under the Connection
tree item. Expend it to reveal Tunnels. Adding a new port forward is as simple
as selecting the Local radio button to create a local port forward, then entering
the source port, which is the port that you'll be connecting to on the local machine, and finally
entering the destination from the perspective of the SSH server you're connecting to
followed by a colon and the remote port you want to use. (You can refer to
this screen capture.)
You can add as many as you want. Next, you'll probably want to move back to the SSH
tree entry and select Don't allocate a pseudo-terminal under Protocol options
if you only want to use this particular connection profile for port fowards. If you'd like to also
have an active SSH session running, do not choose the aforementioned option. Finally,
you may wish to look at the Encryption options section and move the Blowfish
cipher to the top and it will become the most perferred cipher. (Here's
another relevant screen capture.)
Configuring and Using Keychain on a Debian GNU/Linux box
Encrypted SSH tunnels can be used quite effectively for a variety of things. For example, I use an SSH tunnel to access my IMAP server at home from the office. With port forwarding, much like the VNC example above, I connect to the local machine, which connects back to my home network over the SSH tunnel. Effective.
However, each time, you need to enter your password at the login prompt. This is, however, entirely unnecessary and vunerable to replay attacks. A far more secure and convenient (although even more secure when inconvenient) way is to setup an RSA key pair, then connection to the remote machine you wish to initiate a tunnel with via RSA key authentication. You can create an RSA key pair with any recent installation of OpenSSH.
postgres@chosen:~$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/postgres/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/postgres/.ssh/id_rsa.
Your public key has been saved in /home/postgres/.ssh/id_rsa.pub.
The key fingerprint is:
Above an RSA key pair was created with a strong passphrase, using multiple unrelated words and special characters.
To use the keys, simply copy the public key, the one with the pub extension, to the machine you wish to create the tunnel with. This target machine will expect the contents of the pubic RSA key generated above in a file called ~/.ssh/authorized_keys. One approach is to use the cat utility to append the contents of the RSA public key to the end of the authorized_keys file.
postgres@target:~$ cat id_rsa.pub >> ~/.ssh/authorized_keys
Now, when you attempt to initiate a connection (with or without tunneling) to the target machine, it should ask you for a phassphrase for your RSA key, not a password. Keychain takes this a step farther and allows you to enter your passphrase once and maintain it in memory for as long as your machine is up. Only a reboot or Keychain's --clear option will clear it.
Keychain is easy to install. If you're running Debian GNU/Linux simply install the package called, unsurprisingly, keychain. If you will be using the X Window System, you will need to edit etc/X11/Xsession.options and comment out the use-ssh-agent option, since Keychain will take care of this for you. You will need to restart your login manager, if you're using one, after making that change.
Finally, configure Keychain to run from your .xsession or .bash_profile. I setup mine like the following.
jasonb@chosen:~$ cat .xsession
# Let's have some fun
# Use Keychain to ask for my passphrases only once
# Source the result so correct variables are everywhere
. ~/.keychain/`uname -n`-sh
# For ssh-askpass-x11
# Setup our tunnel to fetch mail from my box with needing
# to open 993 on my public IP or manually login at each boot.
ssh -N -T -L 9930:192.168.0.2:993 jasonb@target &
# Finally, start KDE as usual; ssh-askpass might pop up
# the first boot, but not again until the machine is restarted again.
Again, the -N and -T options to OpenSSH prevent the execution of remote commands and the allocation of a pseudo-tty respectively, allowing you to easily background the process. Our friend the -L option allows you to specify the local port, remote server, remote port triplet discussed earlier. Thanks to Keychain you will not be asked for either a password or a passphrase.
Relevant and Useful Resources
Any links herein to products or services are not meant as
an endorsement of the product or service offered.
An excellent VNC through SSH
tutorial that first got me up and running and serves as the basis for
AT&T -- which is also a wonderful phone and ethernet/
provider -- which created VNC via their Cambridge Laboratories, also
of using VNC tunneled through SSH.
VNC List post discussing
tunneling from one machine to another
via an intermediary
also describing an encrypted tunnel via an intermediary.
Linux Journal two part
on setting up VNC access to a running X desktop so your state
is preserved for access from remote locations. (KDE 3.1's new Krfb will allow this out of the box.)
discusses OpenSSH for tunneling and encryption.
home of the latest releases of VNC Viewer and Server for Windows and Unix.
home of the Tight VNC server.
Copyright and Revision Information
09-21-02 - Initial Draft
09-24-02 - Added Links
09-30-02 - Added more article links; Changed VNC link to RealVNC's home
10-13-02 - Added discussion of setting up SSH port fowards using PuTTY
10-13-03 - What an invaluable tool; Added some examples using Keychain
This document is copyright (c) Jason Boxman, 2002. All rights reserved.