Understanding HashKnownHosts: Security Advantages and Practical Implementation in SSH Configuration


1 views

The HashKnownHosts directive in SSH configuration determines whether hostnames and addresses in ~/.ssh/known_hosts are stored in hashed form. When enabled (HashKnownHosts yes), it provides an important security layer by obfuscating sensitive connection information.

Consider this real-world scenario: if an attacker gains access to your system, an unhashed known_hosts file reveals:

  • All servers you regularly connect to
  • Their IP addresses or domain names
  • Potential network topology information

With hashing enabled, this reconnaissance becomes significantly harder as host identifiers are stored as SHA-1 hashes.

While the security benefits are clear, there are practical tradeoffs:

# Example known_hosts entry (unhashed):
example.com ssh-rsa AAAAB3...

# Hashed equivalent:
|1|F1E9Ke...=|k5DZP3... ecdsa-sha2-nistp256 AAAAB3...

The hashing process:

  • Adds minimal overhead during connection establishment
  • Makes manual file maintenance more challenging
  • Requires using ssh-keygen -H -F hostname for lookups

For most environments, I recommend enabling hashing while maintaining these practices:

# In /etc/ssh/ssh_config or ~/.ssh/config
Host *
    HashKnownHosts yes
    IdentitiesOnly yes

When you need to verify a hashed entry:

ssh-keygen -H -F example.com

For teams managing multiple systems, consider these approaches:

  1. Maintain a master unhashed known_hosts in version control
  2. Deploy with hashing enabled via configuration management:
# Ansible example
- name: Configure SSH to hash known hosts
  lineinfile:
    path: /etc/ssh/ssh_config
    line: "HashKnownHosts yes"
    state: present

If you encounter problems after enabling hashing:

  • Verify file permissions (chmod 644 ~/.ssh/known_hosts)
  • Check for duplicate entries (sort -u ~/.ssh/known_hosts)
  • Remember hostnames are case-sensitive in hashed form

While reviewing SSH configurations across multiple servers, I noticed an interesting divergence: some systems had HashKnownHosts yes while others kept it disabled. This discovery prompted me to dig deeper into the actual security implications of this setting.

When enabled, HashKnownHosts transforms entries in ~/.ssh/known_hosts from:

server1.example.com ssh-rsa AAAAB3Nz...

To something like:

|1|JfKT7h6F3+9Pxw3p3OL4iQ==|k5D8L9z2aXvG...= ssh-rsa AAAAB3Nz...

The primary security benefits include:

  • Prevents hostname harvesting: Even if an attacker gains access to your known_hosts file, they can't see which systems you connect to
  • Reduces reconnaissance value for attackers who compromise your account
  • Protects internal network topology from being exposed through the hostnames

To enable globally (affects all users):

# /etc/ssh/ssh_config
HashKnownHosts yes

For per-user configuration:

# ~/.ssh/config
Host *
    HashKnownHosts yes

Legitimate cases for HashKnownHosts no include:

  • When manually managing known_hosts files across multiple systems
  • For troubleshooting SSH connection issues
  • In development environments where hostnames need to be human-readable

You can still verify hashed entries using:

ssh-keygen -H -F example.com

To temporarily disable hashing for a specific connection:

ssh -o HashKnownHosts=no user@host

If switching existing systems to hashed mode:

  1. Back up your current known_hosts file
  2. Run ssh-keygen -H to convert existing entries
  3. Verify connections to critical systems
  4. Update any automation that parses known_hosts