Audit and harden your SSH configuration
Audit and harden your SSH configuration
SSH (Secure SHell) is a commonly used protocol for secure data communications between systems. It is rare to find systems not having this service running. As this opens up a potential gateway into the system, hardening the configuration of the SSH server is an important step in server hardening. In this guide we will focus on several common configuration options of SSH and improve it.
Client and Server
SSH has two parts: the client used for connecting to a server, and the server daemon itself. This latter one is usually the most important part in deciding how “secure” a connection may be. One example is that the server can decide if normal password based logins are allowed or denied. Even if the client has a preference, it is the server to make the final call.
The client configuration settings can be found in /etc/ssh/ssh_config (system wide) or ~/.ssh/config (per user). For the server configuration file: /etc/ssh/sshd_config. Let’s start with the SSH server itself.
Securing the SSH server
Before we start making changes to our configuration, it is a good idea to make a backup.
cp /etc/ssh/sshd_config /root/sshd_config
Before we start with making changes, it is good to know that each OpenSSH version has its own defaults. New features may have been added, older settings may have dissapeared. To know if a specific setting is set, don’t rely on the configuration file. Instead, use the
sshd -T command to see applied values.
The output may look something like this:
Note: configuration settings and values are displayed with lowercase characters.
1. Use of X11Forwarding
The display server on the client might have a higher exposure to be attacked with X11 traffic forwarded. If forwarding of X11 traffic is not needed, disable it:
Why disabling X11Forwarding matters: the X11 protocol was never built with security in mind. As it opens up channel back to the client, the server could send malicious commands back to the client. To protect clients, disable X11Forwarding when it is not needed.
2. Disable rhosts
While not common anymore, rhosts were a weak way to authenticate systems. By default the use of rhosts is already disabled. Make sure to check if it really is.
3. DNS hostname checking
By default, the SSH server can check if the client connecting maps back to the same combination of hostname and IP address. Use the option UseDNS to perform this basic check.
Note: this option may not work properly in all situations, or result in waiting for a timeout during the initial connection. Only use this when you are sure your internal DNS is properly configured.
4. Empty passwords
Accounts should be protected and users should be accountable. The usage of empty passwords should never be allowed for this reason. This can be disabled with the PermitEmptyPasswords option.
5. Maximum authentication attempts
To protect against brute-force attacks on the password of a user, limit the number of attempts. Also enable monitoring for authentication failures, which starts at the half the number of maximum attempts. Use these authentication failures together with your SIEM solution, or forward them to your security administrator.
The SSH server can be configured to be used together with PAM or pluggable authentication modules. By using a set of rules, part of the authentication stack, the number of failed logins can be used to block a particular user. Another option is to define a period to lock the account when this number of attempts has been reached. This way the server can defend better against brute-force attempts to crack a user account and its password.
When limiting the maximum authentication attemps, be aware that public key authentication (see below) can also eat up your number of attempts. If you want to enforce the SSH client (or SCP) to use password-based authentication, use the related options on the command line.
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no username@system
6. Public key authentication
Instead of using a normal password-based login, a better way is using public key authentication. Keys are considered much safer and less prone to brute-force attacks. Disable PasswordAuthentication to force users using keys.
Refer to the article Using SSH keys instead of passwords, to set up key-based authentication.
7. Disable root login
It is best practice not to log in as the root user. Use a normal user account to initiate your connection instead, together with sudo. Direct root logins may result in bad accountability of the actions performed by this user account.
Newer versions of OpenSSH also support the value without-password. This value refers to methods like public key authentication. If your installation comes with this value, there is no reason to change it.
8. Set SSH protocol
If you are running an older system, version 1 of the SSH protocol might still be available. This version has weaknesses and should no longer be used. Since version 7.0 of OpenSSH protocol 1 is automatically disabled during compile time. If your version is older than that, enforce the protocol version:
9. Usage of AllowUsers and DenyUsers
When not all users should have access to the system, limit the number of people who can actually log in. One way is to create a group (e.g. sshusers) and add people to this group. Next set the AllowGroups option to define that only these users can log in.
Other possibilities include to only allow a few users with the AllowUsers, or specifically deny users and groups with the DenyUsers, or DenyGroups. Whitelisting access, using the ‘default deny’ principle, is usually better. So when possible, use the AllowUsers or AllowGroups option.
Good to know: SSH applies the following order to determine if one can log in: DenyUsers, AllowUsers, DenyGroups, finally AllowGroups.
10. Use HashKnownHosts
Each time the SSH client connects to a server, it will store a related signature (a key) of the server. This information is stored in a file names named known_hosts. The known_hosts file itself is available in the .ssh subdirectory of the related user (on the client). In the case the signature of the server changes, SSH will protect the user by notifying about this chance. This option is useful but also has a risk. Previously it was common to store the hostname related with the key. This made it easy for worms and other malicious scripts to use this information and spread to other systems, once they had a single system compromised. To counter this, the HashKnownHosts will hash each host, so it’s not readable anymore. While being unreadable for the human eye, it still allows SSH to check for the next time you connect to the same system, as the results in the same hash.
|1|XV5CFMH8LLIQPq7PxdBhGX7I9PA=|VKNLdODsQlJ/j4cvTZncqs9vgh0= ecdsa-sha2-nistp256 AAAAE2VjZHNhLX….dJ/RzzZLH8Hs0UgroC0=
SSH configuration test
Before restarting your daemon, test if the new configuration is correct.
This command should not return any text or errors. Here is an example when something does not look good:
Read the man page
A good resource for SSH configuration settings is the man page. While this sounds like an easy tip, it is actually useful to know the man page is strong and well-maintained. With all the minor differences between releases, you should never assume what a setting does. Instead, read about the setting and see if it has recent additions. Your configuration of two years ago might already be outdated. Combine this knowledge with the output of
sshd -T and you should be able to select the right option for your situation.
Do you have other SSH settings that we should cover? Let it know it in the comments!