A Practical Guide to Hardening SSH: Ciphers, MACs and Key Exchange Algorithms Worth Disabling
Most SSH hardening advice stops at authentication: use keys, not passwords, maybe add a certificate authority or a hardware key. That is the right priority, but it leaves a second layer completely untouched: the actual cryptographic algorithms your SSH daemon is willing to negotiate. A default install of OpenSSH will still happily offer key exchange methods, ciphers and MACs that were reasonable a decade ago and are not reasonable now. Nobody is going to break AES-256-GCM, but plenty of servers still advertise diffie-hellman-group14-sha1 and hmac-sha1 to any client that asks, and there is no good reason to keep doing that.
This is a walkthrough of the three directives that control this: KexAlgorithms, Ciphers and MACs in sshd_config, plus the related HostKeyAlgorithms. The goal is a config that only negotiates algorithms you'd be happy to defend, and a way to check that before you trust it with your only route into a box.
Seeing what your server currently offers
Before changing anything, find out what is actually being negotiated. From the server itself, sshd -T dumps the effective configuration, resolving all the defaults:
sudo sshd -T | grep -Ei '^(kexalgorithms|ciphers|macs|hostkeyalgorithms)'
From a client, you can list what your local ssh binary supports (not necessarily what a given server offers) with:
ssh -Q kex
ssh -Q cipher
ssh -Q mac
To see what a remote server actually proposes during negotiation, without needing an account on it, the most convenient tool is ssh-audit, which connects, performs the initial handshake, and grades every algorithm the server offers as good, weak or outright dangerous:
ssh-audit example.com
Run that against a box you have not touched in a while and you will usually get a small shock.
What actually needs to go
A few categories of algorithm are worth removing on sight, for reasons that are not really in dispute:
- SHA-1-based key exchange.
diffie-hellman-group1-sha1anddiffie-hellman-group14-sha1combine a hash that is cryptographically broken for collision resistance with, in the group1 case, a 1024-bit modulus that is within reach of nation-state-level compute. Neither belongs on an internet-facing server in 2026. - CBC-mode ciphers (
aes256-cbc,aes128-cbcand friends) are vulnerable to padding-oracle style attacks in the SSH context and have been superseded for years by authenticated modes. - RC4 (
arcfour,arcfour128,arcfour256) has known keystream biases. It has no place anywhere. - Non-ETM (encrypt-then-MAC) MACs and anything based on MD5 or truncated SHA-1 (
hmac-md5,hmac-sha1-96,umac-64) provide weaker integrity guarantees than the ETM variants, which authenticate the ciphertext rather than the plaintext and are not vulnerable to certain length-extension and error-oracle issues. ssh-rsaas a signature algorithm (not the RSA key type itself) relies on SHA-1. OpenSSH 8.8 disabled it by default back in 2021, in favour of the RFC 8332rsa-sha2-256andrsa-sha2-512signature schemes, which use the same RSA keys with a stronger hash. If you have not touched your config since before that release, you may still have compatibility shims re-enabling it.
A config worth actually running
Here is a reasonable baseline for /etc/ssh/sshd_config on a modern Linux box (OpenSSH 9.x), assuming you do not need to talk to genuinely ancient clients:
KexAlgorithms [email protected],curve25519-sha256,[email protected],diffie-hellman-group16-sha512,diffie-hellman-group18-sha512
Ciphers [email protected],[email protected],[email protected],aes256-ctr,aes192-ctr,aes128-ctr
MACs [email protected],[email protected]
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
A few notes on the choices:
- Order matters: OpenSSH negotiates the first mutually supported algorithm in your list, so put your genuine preference first.
[email protected]is a hybrid classical/post-quantum key exchange (Streamlined NTRU Prime combined with X25519); it costs almost nothing in a terminal session and protects against "harvest now, decrypt later" against a future quantum adversary, so there is little reason not to prefer it where both ends support it. - Dropping plain CTR-mode ciphers entirely is defensible too if every client is recent, but AES-CTR without a paired ETM MAC is not itself broken the way CBC is, so it is a reasonable middle tier to keep rather than a hill to die on.
- The client side has the same directives in
~/.ssh/configor/etc/ssh/ssh_config, which matters if you are also hardening the machines you SSH from, not just the ones you SSH to.
The Terrapin attack, and why "strict KEX" isn't optional
It's worth understanding one specific, fairly recent vulnerability, because it changes what "hardened" actually means here. In December 2023, researchers disclosed Terrapin (CVE-2023-48795), a prefix-truncation attack against the SSH transport protocol itself, not against any specific weak algorithm. A man-in-the-middle who can manipulate packet sequence numbers during the unauthenticated part of the handshake can silently delete a chosen number of messages sent immediately after key exchange, before encryption fully kicks in. The practical impact includes stripping the `RFC 8308` extension negotiation, which can be used to force a downgrade, in some client configurations, of keystroke-timing obfuscation or of the signature algorithm back towards SHA-1.
Ironically, the ciphers most exposed were the modern-looking ones: [email protected] (because of how it handles sequence numbers internally) and any cipher paired with an ETM MAC, which is exactly the combination this article just recommended above. The fix isn't to abandon those algorithms; it's a protocol-level countermeasure called "strict KEX", shipped in OpenSSH 9.6, which resets sequence numbers after SSH2_MSG_NEWKEYS and terminates the connection on any out-of-order message during the handshake. It only takes effect when both ends support it, advertised via the pseudo-algorithms [email protected] and [email protected], which OpenSSH adds automatically and which you do not configure yourself.
The takeaway is concrete: algorithm selection is necessary but not sufficient. Check your OpenSSH version is at least 9.6 (or that your distribution has backported the fix, as most did quickly given the severity) before you consider ChaCha20-Poly1305 and the ETM MACs genuinely safe to prefer.
ssh -V
sshd -V
Testing the change without losing access
Restarting sshd with a bad config is the classic way to lock yourself out of a remote box. Before you do it:
- Keep your current SSH session open. Do not close it until you have confirmed a new connection works.
- Validate syntax first:
sudo sshd -tchecks the config file without restarting anything. - Restart, don't reload where possible, so a syntax error surfaces immediately:
sudo systemctl restart sshd. - From a second terminal, open a fresh connection and confirm it succeeds, then re-run
ssh-auditagainst the host to confirm the weak algorithms have actually disappeared, not just been reordered. - Only then close the original session.
If you manage more than one host, this is also a good candidate for a small Ansible or shell-script rollout with a delay and automatic rollback (a cron job that reverts sshd_config and restarts the service after five minutes, cancelled once you confirm access), rather than trusting yourself to remember step 5 under pressure at 2am on a server three time zones away.
One last thing worth checking: PubkeyAcceptedAlgorithms (formerly PubkeyAcceptedKeyTypes) controls which signature algorithms are accepted for public key authentication specifically, separately from HostKeyAlgorithms, which governs the server's own identity key. It is easy to harden one and forget the other, and doing so leaves a mismatched, harder-to-debug set of allowed algorithms depending on whether the client is authenticating the server or itself.