How to secure SSH server

SSH, or Secure SHell, is the most common communication protocol used to connect to servers. It is the telnet’s successor. The problem with telnet is that the data exchanged between you and the server was not authenticated and encrypted. In other words, in case of MITM (Man In The Middle) attack, the bad guy between the server and you could see everything.

Obviously, it’s not because we use a recommended tool that we don’t have to configure it. It is what we are going to see in this article.

Information and requirements

These elements are to be taken into consideration to follow this article:

Update the system

adrien@archiso ~ $ sudo dnf -y update

About the users

The most important thing you must always keep in mind is that: you will never log in as root. You have no trouble understanding that if the root account is compromised, your system and all the installed services are also compromised, without necessarily realizing it (if the usurper is smart).

The best method would be to create a service account (which can use the sudo command to perform administrative tasks). Maybe, you already have this kind of user, you can use this one to connect to. Otherwise, it is what we will see right away.

adrien@archiso ~ $ adduser -r -s /bin/bash -c "Standard user account" -U -m -G wheel <username>
adrien@archiso ~ $ passwd <username>

Concerning this command:

Note: I read in several articles that it was advised not to use a too generic username (admin, administrator, sysadmin…). I partially agree. First of all, it is not a good idea to create a username with random characters like GxTjaiKHg. Also, there are lists of well known usernames on the Internet that are most commonly used to perform brute-force attacks. So I prefer to take the risk of choosing an intelligible username.

SSH daemon configuration

The configuration file of the SSH daemon is located at /etc/ssh/sshd_config. In this one, do the following modifications.

Disable root login

Again, the root user should never be allowed to log in directly over a network, as this both reduces auditable information about who ran privileged command on the system and allows direct attack attempts on root’s password.

PermitRootLogin no

Authorize SSH key based authentication

Specifies whether public key authentication is allowed.

PubkeyAuthentication yes

Disable empty passwords

When password authentication is allowed, it specifies whether the server allows login to accounts with empty password strings.

PermitEmptyPasswords no

Disable password authentication

Specifies whether password authentication is allowed.

PasswordAuthentication no

Authentication that must be completed

Specifies the authentication methods that must be successfully completed for a user to be granted access.

AuthenticationMethods publickey

Disable host-based authentication

SSH’s cryptographic host-based authentication is slightly more secure than .rhosts authentication, since hosts are cryptographically authenticated. However, it is not recommended that hosts unilaterally trust one another, even within an organization.

HostbasedAuthentication no

Disable .rhosts files

SSH can emulate the behavior of the obsolete rsh command in allowing users to enable insecure access to their accounts via .rhosts files.

IgnoreRhosts yes

Disable X11 forwarding

Specifies whether X11 forwarding is permitted. If you don’t use X11 forwarding, I advise you to disable it.

X11Forwarding no

Do not allow users to set environment options

To prevent users from being able to present environment options to the SSH daemon and potentially bypass some access restriction.

PermitUserEnvironment no

Set a banner

The content of the specified file is sent to the remote user before authentication is allowed.

Banner /etc/ssh/banner

I advise you to put something like this in the file /etc/ssh/banner.

Any unauthorized access to this system is prohibited and will be prosecuted by law.

By attempting to access or accessing this system, you agree that your actions will be monitored and any suspicious use will be reported.

Note: Some of you might think that it’s pretty useless to print this kind of message before authentication. As earlier, I partially agree. In fact, maybe 99.9% of unauthorized access attempts are made by robots and they don’t give a fuck about the banner. But, the last 0.1% (that are human being) will see your banner and that will probably discourage them. And since “Anything that isn’t forbidden is allowed”, if someone gains access to your system, he won’t be able to say that it wasn’t forbidden (although the moral law stipulates it)…

Other recommendations

Changing the port

I have already read in some articles that changing the default port (22) is a good practice. Again, I partially agree because knowing that with a tool like RustScan it is possible to scan 65535 ports in a very short time, it is easy to find the SSH port. So it’s just a way to make the attacker losing a few seconds…

Port knocking

Port knocking is a method that aims at modifying the behavior of a firewall in real time by causing the opening of ports for communication by first launching series of connections on distinct ports in the right order, like knocking on a door. I’ve already written an article on this subject that you can find here.

SSH, shut your mouth

When SSH tries to authenticate via public key, it sends the server all your public keys, one by one, until the server accepts one. One can take advantage of this to enumerate all the client’s installed public keys. If this behavior is problematic for you, you can tell SSH not to present your public keys to the server by default.

Add these lines at the end of your ~/.ssh/config (after other Host directives).

Host    *
        PubkeyAuthentication no
        IdentitiesOnly yes

And then specify what keys should be used for each host.

Host    example.com
        PubkeyAuthentication yes
        Hostname <IP address>
        User <user>
        Port <port>
        IdentityFile </path/to/private/key>

Reminders

Generate a strong SSH key pair

Now that you understand that you need to use an SSH key pair to connect to your servers and not a password, it is important to generate strong cryptographic keys.

adrien@archiso ~ $ ssh-keygen -t ed25519 -a 100 -f ~/.ssh/<key pair name> -C <comment> 
<passphrase>
<confirm>

This will create a private and public key pair files using the Ed25519 algorithm, which is considered state of the art. Elliptic curve algorithms in general are sleek and efficient and unlike the other well known elliptic curve algorithm ECDSA, this Ed25519 does not depend on any suspicious NIST defined constants.

The -a flag specifies the number of KDF (Key Derivation Function) rounds used. Higher numbers result in slower passphrase verification and increased resistance to brute-force password cracking if the keys are stolen. Applying 100 rounds is a good compromise between security and efficiency.

The -C allows you to provide a comment, put what you want.

Best way to copy the public key to a server

When password authentication is enabled on a server (just after a fresh install), you can copy the public key to it like the following.

adrien@archiso ~ $ ssh-copy-id -i ~/.ssh/<key pair name>.pub <user>@<IP address>
<user's password>

The public key is now copied into /home/<user>/.ssh/authorized_keys file.