Securing a SSH server

Secure Shell is a prime target for any attacker wanting to gain access to your machine, the default configuration is reasonably secure, but there is plenty of room for improvement, this is particularly important when setting up a machine for the first time over SSH, attacks can and do occur within hours so securing it must be done quickly.

You would think that this is pretty obvious, but it is still surprising how often people choose weak passwords, you generally don't need to go over the top with them to be secure against attack, a few basic guidelines are:

• Use at least 8 characters
• Do not use any common words
• Add numbers and or symbols

Public key authentication

Public key authentication allows you to avoid using passwords entirely, which is very convenient, this is done by generating a key pair on your machine, which consists of a public key and a private key, the public key is added to the authorized_keys file on the server, typically '~/.ssh/authorized_keys' for a specific user, the users SSH client then authenticates by decrypting a challenge that is sent by the server using their public key, this ensures that only the person with the matching private key can login.

The most obvious downside to this is you need to keep the private key safe, you can optionally add a passphrase during key creation for more security but on the whole using public key authentication without a password is safer than just a regular password, password authentication can be disabled on the server making brute force attacks practically impossible.

The key pair is created by using the 'ssh-keygen' program, a number of different cryptographic algorithms are available but for optimal security RSA 4096 bit and ed25519 are the only recommended choices, the latter is preferred due to the smaller key size and greater speed, but may not be compatible with all software.

ssh-keygen -b 4096 -t rsa
ssh-keygen -t ed25519

Example usage:

\$ ssh-keygen -t ed25519 Generating public/private ed25519 key pair. Enter file in which to save the key (/home/user/.ssh/id_ed25519): ~/.ssh/test_ed25519 Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in test. Your public key has been saved in test.pub. The key fingerprint is: SHA256:k1mQZaxnwsaoQlOZtAWSnyisZhOSK1i8qPp3m0eRhqw test@hostname The key's randomart image is: +--[ED25519 256]--+ | .oo+. .+o | | ..+o .o. | |.o +.o = o. | |+o* o + X+o | |+*.o o oS= | |*+o E .. | |= .. . | |. . ... | |o... .oo | +----[SHA256]-----+

This will generate '~/.ssh/test_ed25519' and '~/.ssh/test_ed25519.pub', the public key 'test_ed25519.pub' can then be added to the server, either manually or using the 'ssh-copy-id' program which requires establishing a regular SSH connection, for example:

ssh-copy-id -i test_ed22519.pub remote_server.com

If the remote user is different from the local user simply use user@remote_server.com instead, if you have password authentication disabled this method is not possible. Here is an example of the manual method with root connecting and the test user account already existing.

scp ~/.ssh/test_ed25519.pub root@remote_server.com:/home/test/ ssh root@remote_server.com mkdir -m 700 /home/test/.ssh chown test:test /home/test/.ssh cat /home/test/test_ed25519.pub >> /home/test/.ssh/authorized_keys chmod 600 /home/test/.ssh/authorized_keys chown test:test /home/test/.ssh/authorized_keys rm /home/test/test_ed25519.pub

This does the following:

• Transfer public key to '/home/test' on the remote server via Secure CoPy
• Connect to remote server as root
• Create the .ssh directory and set permission
• Copy the public key in to authorized_keys file and set permission
• Remove the public key file

Once that is done the user can connect to the remote server, if the private key is in ~/.ssh and named id_ed25519 (or as appropriate) it will be automatically used, alternatively it can be specified manually with the -i argument, if the key requires a pass phrase you will be prompted for it.

This is strongly recommended once you have public key autentication setup, simply add the following to '/etc/ssh/sshd_config' and restart the daemon with 'systemctl restart sshd'

PasswordAuthentication no

Use Sshguard

If you really need to have password logins enabled it is strongly recommended you use sshguard, this program monitors login attempts and can ban temporarily or permanently if there are too many failures, it supports a number of firewalls including the easy to use ufw, you can read more about configuring it here.

Use strong encryption only

Without going in to extensive detail the following algorithms have been chosen with maximum security in mind, weak ones are not included it all.

Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes256-cbc KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 MACs umac-128-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

Note: The space between lines is important.

Having root login enabled is completely unnecessary, if you need root access you can use 'su' or 'sudo' from a regular user.

PermitRootLogin no

Disable forwarding

If you are not using features like X11 forwarding, ssh-agent forwarding and so on you can and should disable them, you can do this individually or disable all forwarding with:

DisableForwarding yes

Use an different port

Using the default port 22 is essentially waving a big red flag, unless you have a specific reason to stick to port 22 you should use something else, this is much less useful if you have other common services running on the same server like HTTP.

Conclusion

There are a few more options that can be used to improve security so I suggest reading the 'sshd' and 'sshd_config' man pages, however for the vast majority of users this is more than sufficient to guarantee security against most attacks.

Below is a full example sshd_config.

# This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. Port 22 #Port 12400 #AddressFamily any #ListenAddress 0.0.0.0 #ListenAddress :: # Use 'sudo ssh-keygen -A' to generate default keys HostKey /etc/ssh/ssh_host_ed25519_key AuthorizedKeysFile .ssh/authorized_keys PasswordAuthentication no PermitEmptyPasswords no PermitRootLogin no ChallengeResponseAuthentication no UsePAM yes DisableForwarding yes Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes256-cbc KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 MACs umac-128-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com # override default of no subsystems Subsystem sftp /usr/lib/ssh/sftp-server