I recently came across this article on the FAIRWARE ransomware attacking Linux servers by brute forcing SSH according to the referenced article here. I thought why in this day-and-age is brute forcing SSH from the Internet working? Surely we are not exposing SSH administrative interfaces to the big bad Internet, let alone in an insecure way (rhetorical)?
So, whilst by no means a complete How-To, I thought I would go through a few areas that I hope may improve the security of systems running SSH. Though, as we all know, what you actually do depends on your risk appetite among other things.
In summary this is really about defence in depth. Not only make good security decisions, but also don't rely on a few. My view is if there is a shortcoming, no matter how minor, deal with it (assess it, then either fix it or accept the risk (with possible mitigations)).
For SSH, in no particular order.
1. Don't bind to all interfaces and certainly not your Internet facing one
In today's world of virtualisation, there really should be no excuse for not re-configuring a management service such as SSH to only listen on a management interface. Such a management network must not be directly accessible via the Internet; you should need to go via a VPN, Citrix or other strong security gate as a minimum to access such a network.
If your management services are only listening on your management interface, then even if your firewalls, or other Internet facing protections are breached, it is still going to be a bit of a challenge for an adversary to get shell access via that service.
This can be achieved using the Listen directive in sshd_config.
2. Never, ever, allow direct privileged logons
Being able to directly SSH (login) as root or a privileged user is just asking for trouble. Would you build a safe so that the door was accessible via an outside wall that the public walk past? I hope not; so should we really be doing the same thing with our servers holding our sensitive information assets?
The easiest way to prevent this is to only permit normal users (typically having a common group). i.e. we whitelist accounts rather than blacklist, so if a new account is created it needs to be assessed first.
PermitRootLogin should always be set to no, but we also need to take account of other 'unprivileged' users that may be applications (thus have access to or “own” potentially sensitive information) and users with enhanced 'root' rights (such as having capabilities in Linux, or via sudo).
3. Multi-factor authentication
It is always a good idea to examine a technology to fully understand what it can do. So, in this case, even if you don't have true multi-factor authentication, you would have spotted the RequiredAuthentications or AuthenticationMethods directive in SSH, which states what methods must succeed to allow access.
So the following on CentOS 7 requires both a publickey and a password to successfully log on (or more precisely the use of the associated private key on the client where the public key is configured on the user's account on the server).
So, even if the public key does not have a paraphrase, we have the following, showing the public key authentication is not sufficient; you also need the account password.
I hope you would agree, even brute forcing that “poor-man's 2FA” is a bit more challenging.
4. Bar tunnelling over SSH
A tunnel allows you to tunnel any connection in any direction, via the SSH connection. Indeed the man page describes how to set up a VPN as well! This allows trivial bypass of firewalls and other security devices, by using the trusted encrypted SSH connection.
Unless you have very specific requirements, which are documented and limited by the configuration such as PermitOpen or the use of a directive in a cert, disable SSH tunnelling via PermitTunnel no. Don't forget the tap devices, if supported.
Even if you have a captive client, the user can press ~C to open an SSH “command line” to dynamically add a tunnel. So, if it isn't disabled at the server side a user can still add it in a captive setup. See the man page on ssh.
5. Require strong MACs and Ciphers
If both the client and server supports it, shouldn't we actively prevent the use of weak MACs and Ciphers?
The default configuration on CentOS 7 allows MD5 and SHA1 as MACs. It also allows sha2-256, sha2-512. Perhaps we should specify only the strongest subset and thus put a mandatory bar on MD5 and SHA1, for example.
6. Use only SSH version 2
Fortunately most modern configurations only enable version 2 (Protocol 2). Protocol version 1 has known design flaws, so should not be used. See an example from CERT here.
7. Client side
Don't forget the client side configuration as well.
If a client also only allows strong MACs and Ciphers, for example, and you suddenly can no longer access a host due to cipher support, does this suggest a problem? Certainly worth investigation.
This is just a small sample of the options open to you. There are many other configuration options for example, including Match statements for finer-grain configuration, adding options in the authorized_keys file, client IP lockdown, and SELinux tweaks, to name a few.
Oh, and monitoring. An unmonitored log is a useless log.
What would be your top recommendations?