Host Key Verification¶
SSH's protection against man-in-the-middle attacks rests on two checks,
and SSHClient performs both during every Connect:
- Signature — the server signs the key-exchange hash with its host key; the client verifies this, proving the server owns the key it presented.
- 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.
@revokedentries 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 byHashKnownHosts yes— the Debian/Ubuntu client default — orssh-keyscan -H) are matched via HMAC-SHA-1, so pointingKnownHostsFileat your real~/.ssh/known_hostspins hosts that were recorded hashed. Whenaccept-newrecords 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:
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.