How to (further) ensure SSH security?

Do as many mitigations as you can.

Your goal is to force a wide variety of potential attackers to spend more effort, resources, computer time (and thus electric bill), and most especially "skilled" (rare or scarce, and thus valuable) person-hours. No one protection works against every threat. Not every threat can be protected against while still remaining on the internet.

However, a large number of threats (script kiddies and low skilled or low resourced attackers) can be defeated almost all the time by having a defense in depth - many layers of good, solid security, each of which should - theoretically - be enough to defeat many threats on its own. Thus, when your system's iptables rules let someone in by accident, the SSHD certificate authentication keeps them out. When your SSHD service has a flaw, your VPN prevents anyone from seeing it. When both your VPN and your SSHD have a flaw at the same time, your firewall rules prevent most of the world's IP addresses from even attempting it, leaving only locals and large botnets to be able to try and exploit the vulnerabilities, which you patch as soon as possible.

Thus, I say again, put in as many mitigations at as many levels as possible. You cannot know in advance which ones have undiscovered vulnerabilities, and which order those will be exploited in.

  • Make certain you only allow SSH v2

    • sshd_config

      • Protocol 2
  • Stay patched

  • Use your iptables to allow ONLY the IP addresses or ranges you actually use

  • Set up your SSH to allow access ONLY by certificate, not by username/password, per the Ubuntu help site SSH/OpenSSH/Configuring page

    • sshd_config

      • PubkeyAuthentication yes

      • PasswordAuthentication no

    • If you use an encrypted home directory

      • AuthorizedKeysFile /etc/ssh/%u/authorized_keys
    • If not, the normal setting for home directories can work

      • AuthorizedKeysFile %h/.ssh/authorized_keys

      • Make sure there's not excessive permissions to it.

        • chmod 700 ~/.ssh

        • chmod 600 ~/.ssh/authorized_keys

        • chmod go-w ~

    • And set up as strong a certificate as you can. Generating keys is covered at the Ubuntu help site SSH/OpenSSH/Keys page

      • I'd start with a 4096 bit RSA key or an ed25519 key with a long, strong passphrase. Be sure to generate it locally, type in a long, strong passphrase when prompted, use -o to ensure the new OpenSSH 6.5 key format, and make sure the server never has anything but the public key.

        • ssh-keygen -o -t ed25519 -f ~/.ssh/id_ed25519

        • ssh-keygen -o -b 4096 -t rsa -f ~/.ssh/id_rsa

        • To check length on an existing key, use ssh-keygen -e -f mykeyfile

    • If you can, restrict keys in the authorized_keys file to a specific IP address or set of hostnames

    • If you're on OpenSSH 6.8 or higher, you can restrict authorized keys to certain types as well in sshd_config

      • PubkeyAcceptedKeyTypes ssh-ed25519*,ssh-rsa*
  • Use fail2ban to make brute force attempts take more effort (i.e. make them use a botnet instead of only one machine, or make them take a lot of time)

    • Setting up certificates (keys) is superior if you're asking which one to do first
  • Reduce your login grace time

    • If you're using certificates, you have the option to crank it WAY down unless you use very, very slow connections

      • LoginGraceTime 8
    • Otherwise, well, how fast do you type?

      • LoginGraceTime 20
  • Control your cipher suite choices with information from Mozilla.org Security/Guidelines/OpenSSH

    • Since it's your server, and only you are getting in, you can select a very, very tight grouping such that only the most modern clients are allowed. Perhaps

    • HostKey /etc/ssh/ssh_host_rsa_key

      • sudo ssh-keygen -o -N '' -b 4096 -t rsa -f /etc/ssh/ssh_host_rsa_key

        • or

        • HostKey /etc/ssh/ssh_host_ed25519_key

        • sudo ssh-keygen -o -N '' -t ed25519 -f /etc/ssh/ssh_host_ed25519_key

      • obviously match your HostKey filenames exactly!

        • or both (most preferred first)

        • remove all dsa keys entirely; they're fixed at a pathetic 1024 bits for SSH

    • Use ssh -Q directives to determine what your system supports for the cipher suite options

    • KexAlgorithms [email protected]

    • Ciphers [email protected],[email protected],[email protected]

    • MACs [email protected]

    • Or whatever specific choices make you feel safest

    • And keep up with the literature; when there's a flaw in something you've chosen, choose something that doesn't have known flaws at that point in time.

  • Use your iptables (or firewall) with blocklists from I-blocklist

  • Use your iptables (or firewall) with geographical or ISP based IP lists; one such source of geographical lists is maxmind.com

  • Switch to a port in the dynamic (ephemeral) port range of 49152 to 65535 per RFC6335

    • And only bind to the IP addresses required
  • Block everything other port on that server via iptables; chances are you're getting hit by a LOT of attacks

    • Especially harden your MySQL database, if any - I see a LOT of MySQL (and SQL Server) attacks on my IDS, and I've never run either one or had either port open. Set them to local, non-routable IP's only, etc., long passwords, disable them, etc.

    • Especially disable any web servers, set them to local, non-routable IP's only, etc.

  • Use port knocking per the Ubuntu help site or a DigitalOcean article

  • Rate limit new connection attempts, per this answer to ServerFault question "Hundreds of failed ssh logins"

iptables -A INPUT -p tcp --dport 22 -m recent --update --seconds 60 --hitcount 5 --name SSH --rsource -j DROP

iptables -A INPUT -p tcp --dport 22 -m recent --set --name SSH --rsource -j ACCEPT

  • Consider using chroot per the Debian documentation "OpenSSH SFTP chroot() with ChrootDirectory"

  • Ensure rhosts is disabled with the sshd_config option

    • IgnoreRhosts yes

    • RhostsRSAAuthentication no

    • RhostsAuthentication no

  • Add more restrictions to the pre-authentication unprivileged process

    • UsePrivilegeSeparation sandbox
  • If you aren't using fowarding or tunnelling, disable it in sshd_config

    • X11Forwarding no

    • AllowTcpForwarding no

    • GatewayPorts no

    • PermitTunnel no

  • Prevent other insecure setup in directories or permissions

    • StrictModes yes

    • And then go through your permissions and settings until it works again :)

  • Disable host based authentication

    • HostbasedAuthentication no
  • Note that per This Serverfault answer to "OpenSSH daemon ignores ServerKeyBits directive", the old ServerKeyBits sshd_config directive is no longer applicable, since you don't allow SSH v1 in the first place.

  • Don't allow root in sshd_config

    • PermitRootLogin no
  • Don't allow different users - perhaps service users on some package you install - to have other options

    • PermitUserEnvironment no
  • Install a separate, all-up firewall like pfSense or a Ubiquiti Edgerouter Lite between that machine and the outside world.

    • And then use the built-in VPN IN ADDITION TO your hardened SSH login

    • Also with certificate based logins, not username/password based logins

    • If you use OpenVPN

      • Make sure to use a --tls-auth "ta.key" pre-shared key as well

      • And choose better ciphers than the default

    • And use the blocklists mentioned above at this level also

As DeerHunter mentioned, changing ssh and/or iptables and/or other firewall settings without any other way in can result in a lack of ability to SSH in.


Here you go:

  • Generete SSH keys + protect them with password
  • Allow only specific user to login (AllowUsers)
  • Allow from specific IP [email protected]
  • Change default port
  • Create firewall rules
  • and last thing install fail2ban.