Over some years using OpenSSH for remote network access, I've found a lot of useful tips and tricks that don't seem to be collected anywhere, and seem to be scattered in a bunch of really obtuse manual pages, articles on the subject in assorted web pages, but no real unified spot where any of them can all be found (like an OpenSSH HOWTO for instance). Here's a start. The more I learn of how to use this program's many, many features, the more I'll add to this wu.

Most of the stuff I'll be detailing below applies only to SSH version 2: I pity the fool who is still using SSH1!

Public key-based authentication

This, in my opinion is one of the really neat features of OpenSSH and its cryptography. I imagine a lot of people are still using cleartext passwords tunneled with OpenSSH's encryption, and while this is very good (a fair sight better than telnet or rsh of course!), you can do one better by using authentication based on public key cryptography.

While tunneled plaintext passwords are fine, they are still potentially vulnerable to traffic analysis attacks, most especially if you use a weak password. An attacker can guess, from the amount of traffic exchanged between your host and the server you are attempting to log onto, how long your password is, and by measuring how long it takes for you to type the characters in your password (and some assumptions about what kind of keyboard you're using to enter it), make an educated guess at what are the likely characters in the password. Public key-based authentication makes this problem go away by using a zero knowledge authentication protocol that is able to prove to the server that you possess the private key corresponding to the public key that it knows is supposed to identify you, without revealing the private key. After you have entered a passphrase to decrypt your private key, the process takes place without any further human intervention, and takes an amount of time that does not depend on the nature of the secret information involved.

To do this, of course you need to create a public/private key pair for use with this. This is accomplished by using the ssh-keygen utility. For example:

$ ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/home/you/.ssh/id_dsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/you/.ssh/id_dsa.
Your public key has been saved in /home/you/.ssh/id_dsa.pub.
The key fingerprint is:
be:1d:fc:64:bd:ce:78:63:87:0e:45:c1:44:2c:0a:34 you@host.example.com
$

This command will create two files in the .ssh/ directory in your home directory id_dsa (private key) and id_dsa.pub (public key). The private key file is encrypted with the passphrase you entered, but guard it jealously nevertheless, and leave it only on systems you know you will use to log onto the host(s) you will be using this public/private key identity. Of course you should always enter a passphrase, unless you really know what you are doing! Then you can copy the public key over to the servers that you are planning to use:

$ scp ~/.ssh/id_dsa.pub you@server.example.com:~/.ssh/authorized_keys
you@server.example.com's password:
id_dsa.pub             100% |*****************************|    601       00:00    
$

Now, provided the permissions are correct (~/.ssh on the destination host must have a permissions mask of 700 or 500, allowing read/execute (and optionally write) permissions only to you, and the server has been configured to allow public key authentication (i.e. the PubkeyAuthentication parameter in the /etc/sshd_config file has been set to yes) the next time you try to log onto server.example.com, you should get something that looks like this:

$ ssh server.example.com
Enter passphrase for key '/home/you/.ssh/id_dsa:
Last login: Sun Dec 8 10:36:48 2002
$

Instead of asking you for your password, it asks for the passphrase you used to encrypt the private key. This passphrase is never sent across the network in any form: it is used only to unseal the private key which is used for the zero knowledge protocol with the server.

The disadvantage of this system is, of course, the private key must always be present in order for any of this to work. The simplest and most cost-effective way is to keep the private key on removable media (like a diskette), but the best way given present technology is of course to keep the keys on a smart card; OpenSSH has support for most such devices if you have readers and cards. Best idea would be to disable tunneled cleartext passwords by setting in /etc/ssh/sshd_config the PasswordAuthentication parameter to "no".

The SSH1 protocol also has support for this, and it works in pretty much the same way, but please, for the love of God stop using that b0rken protocol!

The public key infrastructure problem and OpenSSH

OpenSSH makes use of public key/private key pairs to identify servers to clients using a protocol similar to the zero knowledge protocol previously described for user authentication, and as such potentially suffers from the public key infrastructure (PKI) problem: the problem of assuring that a given public key actually does indeed properly identify a given server you are trying to connect to. As the famous dsniff tool has demonstrated, it is easy enough to exploit this problem and perform a man in the middle attack. Despite the fact that dsniff only includes tools that work with SSH1 (yet a further inducement to upgrading to SSH2 if you haven't already), that does not mean that SSH2 is immune to this problem, and it's something you need to be aware about.

To deal with the PKI problem, OpenSSH takes a very simple tack: the .ssh/known_hosts file. Basically, every host public key that it knows about is supposed to live inside this file, giving such relevant information about the host as its IP address and of course hostname. These are not certificates, and the responsibility for maintaining the integrity of this file is totally up to you, which is why OpenSSH is really only suitable for small- to medium-size networks. Unfortunately, OpenSSH takes a fairly slapdash approach to the maintenance of this file, so most default configurations give you a cryptic message that looks like this when you try to connect to a host whose hostkey is unknown:

$ ssh server2.example.com
The authenticity of host 'server2.example.com (192.168.100.2)' can't be established.
RSA key fingerprint is 22:19:4a:6c:9a:b5:f8:9b:0f:cc:31:55:c2:73:ff:bb.
Are you sure you want to continue connecting (yes/no)?

Before you answer 'yes', take a moment to understand what the hell all of this actually means and what the possible consequences are. What OpenSSH is trying to tell you is that a host you are connecting to has an unknown hostkey, and is attempting to get you to decide for it (as there being no real PKI to speak of to help automate this process) whether or not to accept the key as being valid. The odd string of hexadecimal numbers is the key fingerprint, which you are supposed to crosscheck out of band with the actual key fingerprint, similar to the way PGP gets you to verify public keys. If you say 'yes', effectively you are certifying the received hostkey to be valid.

If you make this decision uninformed, you run the risk of accepting the hostkey from a man in the middle's machine, and all traffic between you and the server you are connecting to is clearly visible to the attacker, and it can be maliciously modified for nefarious ends. The key-based authentication protocol described above helps to mitigate these effects as after your login session ends the attacker still can't log into the remote system provided you've configured the SSH on the remote end to accept only public key authentication.

A simple way of making this problem easier to deal with is to provide an X.509-style certification authority system. Each OpenSSH installation would have a certification authority's public key certificate installed, and all hostkeys in the network would be certified with this public key. OpenSSH would then use the certification authority's key to verify the host public key certificate it gets. This is not part of the standard SSH protocols, but something that should become part of it in future versions of the protocol.

In the meantime, the best interim solution would be to publish all key fingerprints and show them out of band. To obtain a key fingerprint for a particular host, you just say:

$ ssh-keygen -l
Enter file in which the key is (/home/you/.ssh/id_rsa): /etc/ssh/ssh_host_rsa_key.pub
1024 22:19:4a:6c:9a:b5:f8:9b:0f:cc:31:55:c2:73:ff:bb /etc/ssh/ssh_host_rsa_key.pub
$

on the host whose public key fingerprint you are trying to obtain. Best of all would be to collect all of the valid hostkeys into an authoritative .ssh/known_hosts file that you then distribute to everyone who wants to connect to these machines.

SSH port forwarding

There are, of course, some protocols which do not use encryption and pass unencrypted data in the clear that just stubbornly won't go away due to political reasons or whatnot. For instance, some web upload clients still use FTP for file upload, and SMTP over SSL is complicated to work with as many MUA's have no support for it. The solution is to use OpenSSH's port forwarding feature, that works by connecting to the server via SSH, then connecting to the port of the unsafe service through the server's loopback interface, then forwarding that connection through the SSH connection to a port that the SSH client listens to locally. You can then use a client for the unsafe service to connect to the port locally, but you'll actually be talking to the real service through the secured tunnel provided by OpenSSH. I regularly use this system to provide for secure SMTP connections whenever I send mail. The other advantage of this is that I can send mail using our SMTP server no matter what ISP I am using to connect to the Internet, without making our mail server an open relay. A single invocation of OpenSSH is sufficient to make this happen:

$ ssh -L 8025:localhost:25 mail.example.com -N
Enter passphrase for key '/home/you/.ssh/id_dsa:
After entering the passphrase, the connection is established, and you can now use port 8025 on localhost to connect to the SMTP service on mail.example.com. Because we are using the loopback interface on both ends, that is the only place where unencrypted traffic can be obtained, and to sniff the loopback interface requires you to actually be root on either side.

I'll add to this wu in the future for more tips and tricks for the use of this wonderful cryptographic program as I learn about them. Feel free to /msg me with your tips and tricks and I'll add them here.