Skip to content

Host Key Verification

SSH's protection against man-in-the-middle attacks rests on two checks, and SSHClient performs both during every Connect:

  1. Signature — the server signs the key-exchange hash with its host key; the client verifies this, proving the server owns the key it presented.
  2. Trust — the presented key is compared against a known_hosts file, proving it is the key this server is supposed to have.

Without the second check, any machine between you and the server could terminate the connection with its own key and silently relay your credentials and traffic.

Policies

The HostKeyPolicy field selects the behavior for hosts that are not yet known. A key that differs from the recorded one is always fatal — except under 'none'.

Policy Unknown host Changed key
'accept-new' (default) key recorded, connection proceeds refused
'strict' refused refused
'none' accepted accepted — no MITM protection

'accept-new' is OpenSSH's trust-on-first-use: the first connection pins the key, every later connection enforces it. 'strict' is for production use with a pre-provisioned known_hosts file. 'none' restores the unverified behavior and should be confined to closed test networks.

The known_hosts file

KnownHostsFile names the file; when it is empty the OpenSSH default is used, resolved cross-platform:

Platform Default
Linux / macOS $HOME/.ssh/known_hosts
Windows %USERPROFILE%\.ssh\known_hosts

The format is OpenSSH's own, so the file is shared with ssh itself:

host.example ssh-rsa AAAAB3NzaC1yc2E... comment
[host.example]:2222 ssh-rsa AAAAB3NzaC1yc2E... DyalogSSHClient
@revoked bad.example ssh-rsa AAAAB3NzaC1yc2E...
|1|Mbv365sFnN+W7jqqGpa7bELLWKs=|iLVt0TJVvRPCCYf7tZTNPSz2mOw= ssh-rsa AAAAB3...
  • Hosts on non-standard ports are recorded and matched as [host]:port (port 22 uses the bare name), matching OpenSSH.
  • Host names match exactly (case-insensitive); wildcards are not supported.
  • @revoked entries are honored: a matching revoked key is refused, in both plain and hashed form.
  • @cert-authority, non-RSA, and comment/malformed lines are skipped.
  • Hashed entries (|1|salt|hash, produced by HashKnownHosts yes — the Debian/Ubuntu client default — or ssh-keyscan -H) are matched via HMAC-SHA-1, so pointing KnownHostsFile at your real ~/.ssh/known_hosts pins hosts that were recorded hashed. When accept-new records a new host into a file that already contains hashed entries, the new entry is written hashed too, following the file's convention.

To pre-provision keys without connecting first:

ssh-keyscan -t rsa -p 2222 host.example >> ~/.ssh/known_hosts

When verification fails

HOST KEY VERIFICATION FAILED for [host.example]:2222: server presented
ssh-rsa key SHA256:mhH2Nyi… which does not match the key recorded in
/home/alice/.ssh/known_hosts — possible man-in-the-middle attack

The connection is refused before any authentication material is sent. The fingerprint in the message is the standard SHA256: form, comparable with ssh-keygen -lf. If the server's key changed legitimately (a reinstall), delete its old line from the file and reconnect; do not switch to 'none' to make the message go away.

Never work around a verification failure blindly

A changed host key is exactly what an attack looks like. Confirm the key change out-of-band with the server's operator before removing the pinned entry.