SSH (Secure Shell) is a network protocol that provides users secure access to a remote system. It provides a strong encrypted data communications channel between two computers over an unsecured network. SSH is the preferred connection method for Linux / UNIX system administrators for operations and maintenance. Although SSH provides much more security that other connectivity methods, if not properly configured, it can be vulnerable. With this article we aim to provide guidance to help you secure and harden your SSH daemon.

This tutorial will explore a lot of options. Not all options are feasible for every server. Only you know your environment, the user base, and the significance of the data on the server. It is up to you, your companies security policies or some other entity within your organization to decide which configuration is right for your system.

Important Information About this Tutorial

The following items apply to this tutorial unless otherwise noted:

File edits should be done to the sshd_config, NOT ssh_config (Notice the d after ssh).

Any changes to the SSH configuration require a restart of the service to take effect.

MOST of the options we will discuss will already be in the sshd_config file. It may be prudent to check if the option exists already in the config file. If it does, you can potentially have conflicting settings.

There are a lot of commented lines in the SSH configuration file. If a line starts with a hash symbol ( # ) then it is a comment and not read by the daemon. In order for that setting to take effect you will need to remove that hash symbol.

A commented line usually shows you the "default" for that option.

Use the SSHv2 Protocol Only

SSHv1 ia a known insecure implementation of the SSH protocol. To ensure the integrity of your system, you should configure the SSH daemon to accept only SSHv2 connections.

To configure the SSH daemon to only use SSHv2 protocol ensure the following line is in the sshd_config file and not commented out.

Protocol 2

NOTE: Versions of Red Hat and CentOS after 7.4 use SSHv2 by default. I still like to put this line in the config file.

Turn Off or Delay Compression

SSH can use gzip algorithms to compress data. If vulnerabilities exist in the compression software, it could result in a compromise of the system.

A lot of discussions have been had on whether or not compression is actually necessary on fast connections. It is widely believed that compression actually slows down the process unless being used over a slow connection (modem, ISDN, etc). If you have to use compression, use the delay feature to ensure the the user is authenticated first before compression starts.

To turn off compression uncomment, edit or add the following line to sshd_config:

Compression no

To delay compression until after a user is authenticated add:

Compression delayed

No compression is my preferred configuration.

Limit Maximum Authentication Attempts

Limiting the maximum times someone can fail authentication is a good way to mitigate brute force attacks. Settings MaxAuthTries to a low number will force disconnect the session after X number of failed attempts.

To limit maximum authentication attempts uncomment, edit or add the following line to sshd_config:

MaxAuthTries 3

You can set this number as low as you like, but 3 is a good balance between security and convenience in my opinion.

Deny Root Account Logons

If you allow root logins, you cannot directly link an action to a user. Forcing users to login with a user specific account assures accountability. In addition it further secures the root account from other types of attacks.

To prevent users from logging on as root uncomment, change or add the following line in sshd-config:

PermitRootLogin no

This configuration is highly recommended.

Display Last Login Date & Time

This is usually the default on most modern systems, but it is still important to check. Printing the date and time of the last login allows the user to recognize unauthorized account use. This will lead to reporting of any unrecognized access for further investigation.

To ensure your system prints the last logon date and time uncomment, edit or add the following line to sshd_config:

PrintLastLog yes

This is an easy win for security.

Terminate Idle SSH Sessions

Leaving an SSH session open indefinitely is a bad idea because a user may leave their workstation unattended. This may give an unauthorized user a chance to run commands from that unattended workstation. It is a best practice to terminate idle SSH sessions within a short period of time to close that window of opportunity.

The ensure an SSH session will be terminated uncomment, change or add the following line in sshd-config:

ClientAliveCountMax 0



The ClientAliveCountMax option works closely with with ClientAliveInterval. For example, if you want an inactive session to close after 15 minutes, you would set the two options like so:

ClientAliveInterval 900

ClientAliveCountMax 0

Excerpt from the man page about ClientAliveCountMax:

Sets the number of client alive messages (see below) which may be sent without ssh receiving any messages back from the client. If this threshold is reached while client alive messages are being sent, sshd will disconnect the client, terminating the session.

Excerpt from man page about ClientAliveInterval:

Sets a timeout interval in seconds after which if no data has been received from the client, sshd will send a message through the encrypted channel to request a response from the client. The default is 0, indicating that these messages will not be sent to the client.

Whitelist Specific Users

You can whilelist (allow) specific users that are authorized to connect to the SSH daemon. Only users in this list will be allowed access, all others will be denied. This has obvious benefits.

To allow only the users "pfloyd", "rwaters", and "dgilmour" uncomment, edit or add the following line to ssd_config:

AllowUsers pfloyd rwaters dgilmour

You can also deny users by using DenyUsers statements like so:

DenyUsers root ncarter ajmclean hdorough

This is not always feasible, but if your environment can support this configuration it will definitely increase your security.

Prohibit Empty Passwords

Ensure any SSH connections will require a non-empty password string. This does not effect SSH key authentication.

To ensure SSH logons require a password uncomment, edit or add the following line in sshd_config:

PermitEmptyPasswords no

This option is another easy change that is recommended for all but very specific cases.

Enforce Password Complexity Rules

If you are using password authentication, it would be wise to enforce password complexity rules. These rules may be set by your organization, or you can just follow best practices. Some possible rules are:

Force password length to be greater than X

Password must contain at least X number of lower case letters

Password must contain at least X number of capital letters

Password must contain at least X number of digits

Password must contain at least X number of special characters

Password must not contain the username (forward or reverse)

To learn more about forcing password complexity read "How to Force Password Complexity in Red Hat". Although the article specifies Red Hat, it will work on any Linux system using PAM (Pluggable Authentication Modules) which is most modern distros.

Do Not Allow Access via rhosts

The rhosts file is a way to control which trust between systems. If a systems "trusts" another system it will allow password-less logins. This is an old antiquated configuration and should be explicitly denied in the SSH configuration

To ensure SSH does not allow rhosts logins uncomment, edit or add the following line in sshd_config:

IgnoreRhosts yes

The rhosts file is rarely used anymore. It is recommended that this option be set in most SSH configurations.

Do Not Allow Access via KnownHosts

The known_hosts file is used to authenticate servers. When a user initiates a SSH connection it compares the servers fingerprint to the one stored in this file to ensure it is connecting to the correct system.

This builds on the rhosts configuration above an ensures that remote connections require a password.

To tell sshd to ignore the user known_hosts during authentication uncomment, edit or add the following line in sshd_config:

IgnoreUserKnownHosts yes

This setting should be configured in most environments.

Disable Host Based Authentication

This is similar to rhosts or hosts.equiv authentication. In my experience it is rarely used and should be set to no.

To disable host based authentication uncomment, edit or add the following to the sshd_config:

HostBasedAuthentication no

It is set to no by default, but for completeness I would add it to the configuration.

Disable X11Forwarding

The X11Forwarding setting allows for executing a program remotely through an SSH session and having the graphical interface displayed on the client. If there isn't an categorical need for X11Forwarding it should be disabled.

To disable X11Forwarding uncomment, edit or add the following line to sshd_config:

X11Forwarding no

The X11Forwarding option is rarely necessary, we recommend this for most systems.

Use a Non-Standard Port

By default SSH listens on tcp port 22. This is known to everyone and is often scanned by hackers and script kiddies doing recon to determine is SSH is running on a system. Other predictable ports that people run SSH on are 2222 and 2121. It may be wise to stay clear of those as well. Pick any high port that is not a used or registered port. For this example, we will use 9222.

To set the SSH daemon to listen on a non-stanard port uncomment, edit or add the following in sshd_config:

Port 9222

I normally do not change the default ports for systems behind a firewall. If your system is open to the internet or other untrusted networks, this is a good standard practice.

NOTE: Do not forget to change the firewall rules to allow incoming connections on your new port.

Set IP Binding to Specific IP Address

By default SSH will listen to on all IP addresses (0.0.0.0) configured on the machine. You should explicitly bind SSH to a specific IP address, preferably a management address on an isolated VLAN.

To configure IP binding uncomment, edit or add the following line in sshd_config:

ListenAddress 10.0.0.5

This typically goes hand in hand with the port binding.

Protect SSH Host Keys

Protect Private Keys

You should protect Private host key from authorized access. If the private key is compromised, the host could be impersonated. All Private key files should be accessible by the root account (0600) only.

To list the permissions of the private keys in the /etc/ssh/ directory use the ls command.

ls -l /etc/ssh/*key

To change the permissions use the chmod command:

chmod 0600 /etc/ssh/*key

It is possible your systems stores the keys in a different directory. You can determine where they are stored by checking the sshd_config file. Here is a convenient command to grep the file for the HostKey directive.

grep -i hostkey /etc/ssh/sshd_config

The above command should list the host keys and their path set in your configuration.

Protect Public Host Keys

Although not as important as the private keys, you should also protect the public keys. If they are modified the SSH service may be compromised or create a denial of service. These should all be set to writable by only the root account (0644).

To list the permissions of the public keys in the /etc/ssh/ directory use the ls command.

ls -l /etc/ssh/*pub

To change the permissions use the chmod command:

chmod 0644 /etc/ssh/*pub

The public keys are often stored with the private keys, see the above section to learn how to find the directory.

Check User Specific Configuration Files

Users can inadvertently leave their home directory or files world writable (chmod 777 much?). In this case other users have access to modify user-specific configurations and can log on to the server as another user. To stop this we can use StrictModes to check the home directory configs.

To ensure sshd performs strict mode checking of home files uncomment, edit or add the following line:

StrictModes yes

This is recommended, especially for systems with a large amount of users.

Prevent Privilege Escalation

Using privilege separation SSH will create an unprivileged child process to accept incoming connections. After user authentication, SSH creates another process with the permissions of the authenticated user.

This defaults to yes on all systems that I know of, but I thought it was worth discussing. You can manually set it by uncommenting, editing or adding the following line to sshd_config:

UsePrivilegeSeparation sandbox

Using sandbox adds additional restrictions.

Use Public Key Authentication

This may not be feasible on all systems. But using SSH key authentication can provide multiple benefits. Key authentication is much stronger than any password a human can easily remember. It also provides authentication without a password for an added convenience.

To allow public key authentication uncomment, edit or change the following line in sshd_config:

PubkeyAuthentication yes

This defaults to yes on most systems.

To learn how to configure SSH Key Authentication read "How to Setup SSH Key Authentication".

Disable Unused Authentication Methods

Linux administrators know it is best practice to stop and remove any services you are not using. Similarly you should disable any authentication methods you are not using in SSH.

Here we show you how to disable all the authentication methods. Be careful not to disable them all.

Disable GSSAPI Authentication

Advanced configurations and additional authentication methods are available using the Generic Security Service Application Program Interface (GSSAPI). If you are not using this, it should be disabled.

To disable GSSAPI uncomment, edit or add the following line to sshd_config:

GSSAPIAuthentication no

Disable Kerberos Authentication

Again, if you are not using it, disable it.

To disable Kerberos Authentication uncomment, edit or add the following line to sshd_config:

KerberosAuthentication no

Disable Password Authentication

You can disable password authentication if you have configured and tested a superior authentication method.

To disable password authentication uncomment, change or add the following line in sshd_config:

PasswordAuthentication no

Disable Public Key Authentication

If you are using another authentication method, you can disable public key authentication. Leaving public key authentication set to yes is less of a risk than other methods.

To disable public key authentication uncomment, change or add the following line in sshd_config:

PubkeyAuthentication no

Use FIPS 140-2 Compliant Ciphers

Use FIP 140-2 compliance to avoid weak encryption algorithms.

To ensure SSH is using FIPS 140-2 approved ciphers uncomment, edit or add the following line to sshd_config:

Ciphers aes128-ctr,aes192-ctr,aes256-ctr

This limits the ciphers that can be used for SSH. Be sure to test compatibility with any older clients, scripts or applications that may use SSH.

Use FIPS 140-2 Compliant MACs

Use FIP 140-2 compliance to avoid weak cryptographic hashes.

To ensure SSH uses FIPS 140-2 approved Messages Authentication Code (MACs) uncomment, edit or add the following line to sshd_config:

MACs hmac-sha2-256,hmac-sha2-512

Be sure to test compatibility with any older clients, scripts or applications that may use SSH.

Filter Incoming SSH Connections at the Host Firewall

Filtering incoming SSH connections is a good way to secure SSH. Although it is not always feasible. You can allow only specific IP addresses or subnets to connect to your system. We cannot cover all firewalls, but here are examples using iptables, firewalld and Uncomplicated Firewall (UFW).

Filter SSH Connections with iptables

To only allow a specific IP address to connect to SSH using iptables:

iptables -I INPUT -p tcp -s 10.0.0.5 --dport 22 -j ACCEPT

To allow a subnet to connect to SSH using iptables:

iptables -I INPUT -p tcp -s 10.0.0.0/24 --dport 22 -j ACCEPT

NOTE: Change the IP address and port number to match your configuration.

To learn more about iptables please read "The Basics of IPTables".

Filter SSH Connections with Firewalld

To allow a specific IP address to connect to SSH using Firewalld:

firewall-cmd --permanent --zone=public --add-rich-rule=' rule family="ipv4" source address="10.0.0.5" port protocol="tcp" port="22" accept'

To allow a subnet to connect to SSH using Firwalld:

firewall-cmd --permanent --zone=public --add-rich-rule=' rule family="ipv4" source address="10.0.0.0/24" port protocol="tcp" port="22" accept'

NOTE: Change the IP address and port number to match your configuration.

To learn more about firewalld please read "Introduction to Firewalld Basics".

Filter SSH Connections with UFW

To allow a specific IP address to connect to SSH:

sudo ufw allow from 10.0.0.5 to any port 22

To allow a subnet to connect to SSH:

sudo ufw allow from 10.0.0.0/24 to any port 22

NOTE: Change the IP address and port number to match your configuration.

To learn more about UFW please read "UFW (Uncomplicated Firewall) Basics".

Setting a Connection Banner

In my experience this does more harm than good. It may deter some script kiddies, but most experienced crackers will take a sharply worded banner as a challenge. If you do decide to add a banner, I would think about the above when setting the tone of the message.

To set a banner uncomment, edit or add the following line:

Banner /etc/issue

Then edit the /etc/issue file with the verbiage you want displayed when someone connects to SSH on your system.

Optional Programs

There are a host of programs that can be installed to help thwart attacks. The most well known being fail2ban which scans logs for malicious behavior like too many password failures. It then takes an action like updating firewall rules to block the offending IP address.

The complete configuration of fail2ban is outside the scope of this article.

You can find all the necessary information on the fail2ban wiki.

Conclusion

We covered a lot of options to help secure your SSH daemon in this tutorial. As I stated in the introduction the feasibility of each setting is up to you. Only you can scrutinize the convenience versus security of each. Knowing what options are available is always great start and I think we covered most of them.

If you use every setting on this page your configuration will surpass the Defense Information Systems Agency's Security Technical Information Guide configuration standards.