These are steps that I consider reasonable, and to the best of my knowledge are reasonably secure by current standards at the time of writing (20190122). It's important to note that none of these steps, in isolation or in totality are a panacea. Security works best in layers, this is just one that's an easy target on every *NIX host system. Depending on your deployment and your needs, this may be overkill, or insufficient, but has worked fantastically in reducing both the number of bots wasting CPU time, and the amount of CPU time they're able to waste when they're able to even get that far.
This article will consist primarily of snippets from a customized
~/.ssh/config, with annotations
both in comments and surrounding text as needed to explain why certain decisions are being made.
DISCLAIMER: I am not a security expert or a security researcher, just a guy that's kinda passionate about not getting pwned and willing to read the manual for services that I use heavily. While that may as well be a superpower now, don't blame me if you use this information and still get hacked.
The first, and perhaps most obvious tweaks are to have
sshd listen only on the addresses which you expect to be using for management,
for example: if your deployment doesn't require logging in remotely through the WAN interface, don't listen on that interface! You can't attack a service
that isn't there! The second step, which is stated frequently in any group that enjoys self-hosting services or other sysadmin/netadmin type projects,
is to have
sshd listen on a non-standard port, ideally over 1000. This makes it a bit more difficult to be sure that you're running
at all, but is far from foolproof as tools like
nmap will still find your non-standard port. Such a configuration may look like this:
## High, non-standard port Port 3285 ## Allow both IPv4 and IPv6 connections ## Do not set this if you're not accepting both protocols ## Enable only what you'll actually use AddressFamily any ## This can be specified multiple times, once for each address you want to use ## Leaving this as 0.0.0.0/:: will bind to all addresses on the server, make sure you actually want that! ListenAddress 192.168.1.15
The next important step is restricting how clients can even connect to the server, not just restricting logins to use key-based authentication, which you'll hear from practically everyone, but exactly which methods of communicating with the server are considered valid. As before, you only want to enable what you'll actually be using, and in the interest of protecting whatever data is being transferred over your SSH connection, you'll want to find a good balance between being secure, fast, and computationally expensive. The easier it is to compute these steps, the easier it is to brute-force your session details.
## Only use Ed25519 keys, they're currently the most secure, while also being small and relatively quick to use ## This is what's hashed and presented to the clients as our "identity" HostKey /etc/ssh/ssh_host_ed25519_key ## Do not allow an ephemeral session key to be older than 10 minutes RekeyLimit default 600 Ciphers email@example.com,aes256-ctr,firstname.lastname@example.org KexAlgorithms curve25519-sha256,email@example.com MACs firstname.lastname@example.org,email@example.com,firstname.lastname@example.org PukkeyAcceptedKeyTypes ssh-ed25519,email@example.com
~/.ssh/known_hostsafter you type "yes" when connecting to a new server, and what gets compared when
sshwarns you about a possible man-in-the-middle attack. We're only using ED25519 keys because of their efficiency and relative cryptographic strength over the usual RSA/DSA key types. This is also why we set
PubKeyAcceptedKeyTypesto be exclusively an ed25519 key or an ed25519 certificate. The only downside here is that older
sshdsystems may not support this method, which is bad news if you just realized you're running such a system, upgrade as soon as you can, or find other ways to layer some security on top of it. This also means older
sshclients may not be able to log in anymore, so if you're uncertain, run
ssh -Q keyto get a list of supported key types from your client.
default 600means that we'll allow the default amount of data to be transferred, but also ensure that a session key can only possibly be used for 10 minutes at a time. This should make it more time consuming to decrypt any potentially captured data, assuming such an adversary has the resources to break the other options specified.
firstname.lastname@example.org our last resort MAC because of its susceptibility to length extension attacks that could potentially lead to information leakage. To my knowledge, there's no such weakness in UMAC options at this time.
So now we get into the portion of the configuration that actually dictates how to log into the server once the connection is established. By comparison, this portion is quite simple:
LoginGraceTime 5 PermitRootLogin no StrictModes yes MaxAuthTries 2 MaxStartups 2:25:10 PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys PasswordAuthentication no PermitEmptyPasswords no AuthenticationMethods publickey FingerprintHash sha256 AllowUsers user1 user2 DenyUsers root admin student toor
doas, we do not want to allow god mode via remote login. I don't care how secure the rest of your network is, this spells game over for anyone that can actually get in.
sshdto verify the file modes and ownership of the user's files and home directory before allowing logins. This should not be necssary, but I like to know that if my home directory or ssh directory gets messed up,
sshdwon't allow remote login.
sshd, it controls how many concurrent unauthenticated sessions can be running at once, optionally with a rate to drop new unauthenticated connections. So with the setting of
2:25:10, after 2 concurrent unauthenticated connections, we'll drop 25% of inbound unauthenticated connections, with a maximum of 10 unauthenticated connections, after which we refuse to accept any new connections. Keep in mind that the maximum amount of time any singe unauthenticated connection will be alive is 5s.
~/.ssh/authorized_keysfor a matching signature.
ssh, so you can restrict remote login to a subset of user accounts.
These options don't really have a great category to describe them by, and aren't necessarily going to make a difference to your security compared to the other settings already covered, but they can help ensure that your system isn't being abused or indexed appropriately by attakers.
DisableForwarding yes PermitTunnel no VersionAddendum TempleOS
tun(4)device, commonly used to create a VPN.
sshd, it will generally default to your OS version, which is information you'd probably rather not expose to a potential attacker, why make their job easier? As such, I enjoy setting it to report some OS that can't possibly match the utility of the system, such as "TempleOS" or "Windows3.1". Doing so has the nice benefit of screwing up the results of
nmapscans. On its own, it's pretty useless, but it's just one more way you can lie to a potential attacker about what your systems are capable of.
As you may have expected, there's more to SSH than just the server-side hardening, we also have the client-side to worry about!
The options here are not quite so important, since the client will negotiate with the server to determine how to connect, but there's a few things you can do
to ensure you're connecting as intended.
NOTE: If you want to enforce a set of system-wide defaults for all
ssh clients on a server, make these changes to
Host * IdentityFile ~/.ssh/id_ed25519 PasswordAuthentication no ConnectionAttempts 2 ConnectTimeout 20 HashKnownHosts yes VerifyHostKeyDNS yes VisualHostKey yes StrictHostKeyChecking yes
~/.ssh/known_hostsis hashed, which is primarily useful for obfuscating what servers and on which portrs you're connecting to, if this is your sole line of defense, pray your network security is good enough to keep the bad actors out.
sshdisplays the ASCII-art version of the server's host key.
I should note that this page is nowhere near exhaustive in the customizations I've done even to my own
ssh configuratinos, I'm just
touching on the ones that are most important in hardening your server from remote logins. Please refer to your system's documentation on both of these programs
to get more information on what can be done to make them work best for you in your given situation.