69

What are the benefits of storing known_hosts in a hashed form? From what I read, it is supposed to protect the list of servers I am connecting to, presumably in a scenario where my account has been compromised (and known_hosts file stolen)

If my account were indeed to be compromised, having known_hosts hashed would be very little consolation. An attacker could see from my bash history to which servers I am connecting. And also from my .ssh/config where all my servers are listed.

Are there any benefits that I am missing in my description here?

3 Answers 3

72

I don't think you are missing much. The only change is that if a machine is compromised, the idea is to minimize how much usable information is given to an attacker. In the known_hosts file, more information is not necessary to include (computing a few hundred HMACs is not onerous work), unlike in ~/.ssh/config where it needs to be included on the Address line if you wish to connect via your alias (hashing wouldn't work) and in your command line history - if you choose to keep one.

Presumably you could have a very large known_hosts (e.g., if you sync it with another computer when you setup the account), but say not use .ssh/config and not keep a command line history or have never connected to most machines in the commandline history.

In those situations, hashing the IP addresses used in your known_hosts could lessen exposure in the event of a compromise.

Furthermore, HashKnownHosts is a configurable option, and the default is to not hash (probably for reasons you specified -- it doesn't help much). See man ssh_config:

HashKnownHosts

Indicates that ssh(1) should hash host names and addresses when they are added to ~/.ssh/known_hosts. These hashed names may be used normally by ssh(1) and sshd(8), but they do not reveal identifying information should the file's contents be disclosed. The default is “no”. Note that existing names and addresses in known hosts files will not be converted automatically, but may be manually hashed using ssh-keygen(1). Use of this option may break facilities such as tab-completion that rely on being able to read unhashed host names from ~/.ssh/known_hosts.


Note the format of a hashed known_hosts line (example taken from here - my current configuration is not to hash) for an entry for 192.168.1.61:

|1|F1E1KeoE/eEWhi10WpGv4OdiO6Y=|3988QV0VE8wmZL7suNrYQLITLCg= ssh-rsa ... 

where the first part F1E1KeoE/eEWhi10WpGv4OdiO6Y= is a random salt - that acts as a key for the HMAC-SHA1 to hash 192.168.1.61.

You can verify in the command line with (BSD / Mac OS X):

#### key=`echo F1E1KeoE/eEWhi10WpGv4OdiO6Y= | base64 -D | xxd -p`
#### echo -n "192.168.1.61" | openssl sha1 -mac HMAC -macopt hexkey:$key|awk '{print $2}' | xxd -r -p|base64
3988QV0VE8wmZL7suNrYQLITLCg=

or on GNU/linux with:

#### key=`echo F1E1KeoE/eEWhi10WpGv4OdiO6Y= | base64 -d | xxd -p`
#### echo -n "192.168.1.61" | openssl sha1 -mac HMAC -macopt hexkey:$key|awk '{print $2}' | xxd -r -p|base64
3988QV0VE8wmZL7suNrYQLITLCg=

where we just decoded the salt and used it as a key in a sha1 HMAC, and then re-encode the hash in base64. Just specifying as another answer originally presumed that the HMAC may have used the user's private ssh key to compute hash-based message authentication code, but this is not the case.

2
  • FWIW you can remove the awk and xxd -r -p by using openssl sha1 ... -binary. And you could use openssl base64 [-d] -A on all systems. Commented Sep 16, 2020 at 7:12
  • For the record, HashKnownHosts yes is the default on Debian and Ubuntu nowadays => known_hosts uses the hashed form by default. Commented Apr 21, 2023 at 9:20
8

I believe, that there are no benefits of hashing the hostname in the known_hosts file. That hash even provides a false feeling of security. It should be removed as soon as possible. The reason is, that ssh stores each host twice, both by name and by IP address. There are only 2³² = 4294967296 different IP addresses. However, modern GPUs can brute force SHA-1 at a rate of 12 Gigahashes per second:

https://github.com/siseci/hashcat-benchmark-comparison/commit/c1bce983d8bfa4b547c6afaff0210163b4d95af2

In other words: A single GPU unhashes an IP address in less than one second. Using hints from whois $IP, host $IP and the already compromised machine's own hostname, configured username(s), directory names, greeting messages and similiar data as input to a general password breaking / dictionary attack algorithm, the target's hostname will usually be recovered within the next second.

known_hosts would be secure, if each line contained a hash of the public key of the remote host, and if a hash of that public key with a different salt was used to encrypt hostname and IP address. In that case, ssh would not be able to warn, if a foreign key has changed, though. It would just warn of an unknown key, if someone tries a man-in-the-middle attack.

There are more secure modes of operation of ssh, which don't require known_hosts: One can use an institution-wide CA to sign all host (and potentially also client) keys, and allow clients to connect only to hosts, that present such a signed key.

1
  • It is a good point. And one more thing. If I know target IP, I don't need hostname anymore. I can use that IP for making connections.
    – Tomas
    Commented Mar 28, 2023 at 13:11
2

A short addition to the other answers.

You can delete your shell history, but you should not delete your known_hosts file, because it is there to provide "trust on first use" security.
So it is the only file you should not clean up, when trying to minimize the sensible data on the system. To be still able to secure it, you can use hashes.

If you want the small increase in security or rather be able to edit known_hosts by hand and search for hostnames and IPs is up to you. Especially known_hosts is used by bash to complete hostnames when you type "ssh [tab]".

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .