SSH Host Key Protection
by Brian Hatch
This is the first in a series of articles on SSH in-depth. We start with looking at standard SSH host keys by examining the verification process to ensure you have not been the victim of an attack. Please note that this article applies to the widely used OpenSSH application that is bundled with most Unix based operating systems, and not the commercial version of SSH.
SSH Host Keys as a protection against Man-In-The-Middle Attacks
SSH is a ubiquitous protocol that offers secure, encrypted connections for a variety of purposes, including logging into remote machines, transferring files, setting up encrypted tunnels, running remote commands without manual authentication, and more. It was created to replace many non-encrypted protocols such as Telnet, FTP, RSH, and the like.
One of the problems with these old protocols, aside from the fact that they send everything (your password included) in the clear, is that they are vulnerable to man-in-the-middle attacks. A cracker with access to the intermediate network could intercept your packets, log them, and then send them to the actual destination. Even worse, she could re-write your packets, perhaps replacing
SSH offers a crucial feature -- the ability for you to verify the identity of the host to which you're connecting. If you correctly verify the host, then there's no way an intermediate device could be reading or manipulating your packets. [ref 1] Successful host verification indicates that the connection is encrypted end-to-end -- your SSH client has established a secure connection with the SSH server itself, and no intermediate machines have access to that connection.
Host verification is not unique to SSH. Any decent security-aware protocol has some sort of peer verification. For example, let's take a look at HTTPS, the SSL/TLS encrypted version of HTTP. It also offers host verification in much the same way as SSH. HTTPS host verification looks like the following. I've taken the liberty of mapping SSL-speak into SSH-speak to make it clearer to compare later on. [ref 2]
All of these step have their analogue in the world of SSH except for one: there is no Certificate Authority at all. [ref 3] Instead, the 'authority' are your personal and global configuration files, which we'll see later.
SSH Host Keys in Action
Let's see how SSH maps these steps by making an SSH connection to a machine we've never contacted before:
$ ssh ssh-server.example.com The authenticity of host 'ssh-server.example.com (12.18.429.21)' can't be established. RSA key fingerprint is 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d. Are you sure you want to continue connecting (yes/no)?
Let's say we blindly say "yes" here, and the connection will continue:
$ ssh ssh-server.example.com Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'ssh-server.example.com,12.18.429.21' (RSA) to the list of known hosts. Password: (enter password) ssh-server.example.com $
The server presented its host key to the client as part of the initial handshake. The mathematical magic to prove it had access to this key is not seen above, indicating there were no errors in that regard.
Since we've never connected to this machine before, and SSH doesn't have the concept of a trusted third party like Certificate Authorities in the world of SSL/TLS, it's up to you to do all the key management yourself. Your client shows you the key fingerprint, an easy-to-read string of numbers that you can use to check the key manually -- we'll see this later. If you say "Yes, the fingerprint is correct", then your SSH client will continue logging in, allow you to type your password, and let you do your work.
When you said 'yes', above, your SSH client saved the server's host key locally in the file
$ tail -1 $HOME/.ssh/known_hosts ssh-server.example.com,12.18.429.21 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA0 6jFqviLMMJ/GaJNhGx/P6Z7+4aJIfUqcVjTGQasS1daDYejcfOAWK0juoD+zS3BsGKKYKPA 5Gc5M8v+3NHLbPn1yTpDBgl6UzA0iiMPCbwnOLx61MrBTk+/qJI9kyDaJf4LEY6Chx4IJP0 ZN5NmAlCtXQsca3jwFAF72mqPbF8=
(I've taken the liberty of wrapping and indenting this line for clarity.)
Each entry in
The next time you connect to this machine, your SSH client will go through the standard steps of verifying the remote machine and allowing you to log in:
$ ssh ssh-server.example.com Password: (enter password)
Note that, this time, it did not ask you to verify the key fingerprint at all. That's because the key was in your
As you should have noticed, when we connected originally and accepted the key, it stored both the hostname (
Verifying the host key
I've shown you how to connect for the first time and accept the host key. But how do you know you've gotten the correct key? If you connected to the server, but an attacker has intercepted and proxied your SSH connection, she could have tricked you into accepting her key, not the actual host key. We've got a classic chicken and egg problem here.
The best way to verify a host key is to do so in some out-of-band method. For example the owner of the system could publish the key fingerprint on an SSL-protected web page. One place I worked actually distributed the host key of our main shell server on our laminated 'Emergency Contacts' phone number card, so you could verify it just by pulling out your wallet, even when sitting down at an Internet cafe.
If you don't have an out-of-band option, then the next best thing is to check the host key once you have logged in. The public host key is usually world readable in the
Going back to that first connection we made, let's see how we match up the fingerprint:
$ ssh ssh-server.example.com The authenticity of host 'ssh-server.example.com (12.18.429.21)' can't be established. RSA key fingerprint is 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'ssh-server.example.com,12.18.429.21' (RSA) to the list of known hosts. Password: (enter password) ssh-server.example.com $ cd /etc/ssh ssh-server.example.com $ ls *.pub ssh_host_dsa_key.pub ssh_host_rsa_key.pub ssh_host_key.pub ssh-server.example.com $ ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key.pub 1024 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d ssh_host_rsa_key.pub
Above we see the user accept the key, log in, and then view the key with
Host Key Checking Paranoia
SSH has three ways it can react to an unrecognised or changed SSH host key, based on the value of the
Why Can A Host Key Change?
There are several reasons a host key can change or appear to be new. In the case of cracker activity, an error seen during the host key verification phase is the only way you'll know before you log in. However there are some other common problems that are not related to malicious activity that cause host key mismatches.
Types of Host Keys
SSH comes with two major protocols, SSHv2 and SSHv1. [ref 7]
The older SSHv1 protocol relied exclusively on RSA for it's asymmetric encryption, whereas the newer SSHv2 protocol supports ether RSA or DSA asymmetric encryption. An SSH server can use any of the three types of host keys: SSHv1 RSA keys, SSHv2 RSA keys, or SSHv2 DSA keys. I will refer to these as rsa1, rsa, and dsa keys respectively, as this is the terminology used by the OpenSSH tools.
SSH Host Keys are created with the
# Which protocol(s) should we support? Protocol 2,1 # HostKey for protocol version 1 HostKey /etc/ssh/ssh_host_key # HostKeys for protocol version 2 HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_dsa_key
If you were installing from scratch, you'd want to create these three keys using
# ssh-keygen -t rsa /etc/ssh/ssh_host_rsa_key # ssh-keygen -t dsa /etc/ssh/ssh_host_dsa_key # ssh-keygen -t rsa1 /etc/ssh/ssh_host_key
If you doubt that the first file, the one that doesn't end in
$ ls -1 /etc/ssh/ssh_host_rsa_key* /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_rsa_key.pub $ cat /etc/ssh/ssh_host_rsa_key.pub ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEApCyGZbDdzrRdszzQUZI+siu3 /mUI57nmjzKwHS7M27AoMZNJ6yIDTn5J3/MVCDJAeyB53LvIFFD9Kzp6P9 fhNhPm8+b0joJ5Wrn+YfUnt2moI3lkAzQUZI+siu3/mUI57nmjzKwH $ ssh-keygen -y -f /etc/ssh/ssh_host_rsa_key ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEApCyGZbDdzrRdszzQUZI+siu3 /mUI57nmjzKwHS7M27AoMZNJ6yIDTn5J3/MVCDJAeyB53LvIFFD9Kzp6P9 fhNhPm8+b0joJ5Wrn+YfUnt2moI3lkAzQUZI+siu3/mUI57nmjzKwH
Is there any reason to use one type of host key versus another? Not really.
There are a number of tricks that can make managing host keys easier and more secure for you and/or you users.
There are several configuration options which might be useful, depending on how you are using SSH. These can live in either the global SSH configuration file, typically
[ref 1] This is because the cryptography used to protect your session is based on the successful asymmetric encryption used to verify the host.
[ref 2] Note this is description is valid for any SSL/TLS capable service that has peer authentication enabled -- it need not be HTTPS, it could be MySQL or LDAP over SSL, for example.
[ref 3] There are patches to OpenSSH that allow actual X509 authentication, so you can get closer to this model if you desire.
[ref 4] It's always possible that a man-in-the-middle attacker is watching for this verification and can twiddle the output to convince you the keys match. If the attacker is this good, you've got lots of problems ahead of you.
[ref 5] It does, however, disable password authentication, so at least you must use SSH Identities/PubKeys, Challenge/Response, or some other form of authentication that is not reusable by an attacker.
[ref 6] The converse is possible, but unlikely.
[ref 7] SSHv1 is considered the less secure of the two versions. Unless you need to use client software that only supports the older SSHv1 protocol, for security reasons you are best off only enabling SSHv2 in your server. In
# Protocol 2,1 would allow either SSHv1 or SSHv2. # Let's be paranoid and only support the later. Protocol 2
[ref 9] The private key must not be protected because otherwise
[ref 10] The patent on the RSA algorithm expired in 2000.
About the author
Brian Hatch is the author of Hacking Linux Exposed, 2nd Edition, Building Linux VPNs, and of the Linux Security: Tips, Tricks, and Hackery Newsletter. In order to exit an xterm, he frequently needs to log out of ten or more SSH connections, each with cascaded port forwards, to get back to his desktop shell. And that's not even including all the virtual
More articles by this author
View more articles by Brian Hatch on SecurityFocus.
This article originally appeared on SecurityFocus.com -- reproduction in whole or in part is not allowed without expressed written consent.