Hardening the OpenSSH security

Vishal Raj
9 min readAug 20, 2019
Hardening SSH security in Ubuntu
Photo by Jose Fontano on Unsplash

The world is thankful to Linux Torvalds, for he gave us Linux. What began as a personal project, has matured over three decades, so much so that the almost entire Internet runs on Linux. Linux rules from personal computers to enterprise grade computers used by large organizations.

Coming to the idea of this article, when you want to access a remote Linux host from your local host, there are quite few ways to do so.

  • Use secure shell (OpenSSH) to get access to command line interface on remote host
  • Use remote desktop clients such as Remmina, VNC viewer etc for GUI access on remote host
  • Use FTP client such as Filezilla, FireFTP etc, for file transfers between local and remote host

It is assumed, that Linux is secure operating system. Yes it is, but you have to harden the security to ensure that the host remains safe from unauthorized access. Today I am writing about how to harden the secure shell (OpenSSH) access to remote Linux host. I have considered Ubuntu as the operating system.

Beginning with OpenSSH on server & client

For a Linux host to be able to accept incoming SSH connection, it must have openssh-server installed. Or else, run the following command in terminal

sudo apt-get install openssh-server

Similarly, to initiate SSH connection from local host, you need to have openssh-client installed on your local host. Or else, run the following command in terminal-

sudo apt-get install openssh-client

Now that we have openssh-server installed on remote Linux host and openssh-client on the local host, lets begin. From the terminal in local host, run the following command

ssh <remote-user>@<remote-host>

NOTE: Beware that if incorrect remote username is used, the remote host will prompt for password, though the authentication will always fail. And there’s no way for the user to know it.

Hardening the SSH

Enter the password and now you are into the remote host. Whoa, that was simple. But isn’t that a bit insecure? How? What if the password is pretty simple, which can be easily guessed. What is somebody is just overlooking your shoulder? What if your keypress is being tracked? Also, password based authentication is prone to brute-force attacks. Scenarios are many more. So what can be done? In no particular order, here are few tips to harden the OpenSSH security. These changes are required to be done on the remote server in SSH config file — /etc/ssh/sshd_config

IMPORTANT: Please note that changing these settings without understanding the impact can lock you out of the remote host, leaving you without access to it. Please be very very careful.

IMPORTANT: It is strongly advised to keep a backup copy of the original configuration file before making any changes to the configuration file.

Change the default port

By default OpenSSH connects via port 22, but it is recommended to switch over to a different port. A port number is a 16 bit number and so it can range from 0 to 65535. Lower port numbers are reserved for system, so use a higher port number such as 2222, 2255, 2525 or anything higher.

Port <ssh-remote-port>

Use SSH2 instead of SSH protocol

SSH2 protocol has several improvements over old SSH protocol. It is more efficient, secure, portable, has more defensive mechanisms. It uses strong algorithms like DSA for authentication and encryption.

For more details, see — https://searchsecurity.techtarget.com/tip/An-introduction-to-SSH2 and http://www.snailbook.com/faq/ssh-1-vs-2.auto.html

Protocol 2

Disable remote login for root user

Unless there is a very strong reason to keep this setting enabled, disabling remote login for root user can save you a ton of trouble.

PermitRootLogin no

In exceptional cases, you might want to escalate privilege to root user for a set of command(s), for a non-root users login. This can be achieved by updating the key entry against the user in file /etc/ssh/authorized_keys on the remote host. When such user will try to login to the remote host, the command(s) will be execute with root privileges and the ssh session will exit. See the example below

command="<full-command-with-absolute-path> <optional-arguments>; <full-command" ssh-rsa ...

Disable password based authentication and switch to using public key instead of password based authentication

The public-private key authentication is definitely more secure than plain password. You can generate SSH keys (pair of public-private key). The private key is stored on you local host while the public key is copied to the remote host. For more details on how to generate ssh keys and their technical details, see — https://www.ssh.com/ssh/keygen/#sec-What-Is-ssh-keygen

PasswordAuthentication no

Generate a stronger pair of public-private key

In order to generate PPK on client, use the ssh-keygen command. By default ssh-keygen uses 2048 bit RSA for key generation. This can be changed by passing more parameters to ssh-keygen command. For more details, see — https://www.ssh.com/ssh/keygen/

ssh-keygen -t rsa -b 4096

Use strong passwords & passphrases to avoid brute-force attacks

Using password is discourage as it is prone to brute-force attacks. But if it has to be so, use a strong password which Include a combination of capital & small letters, numbers, and special characters. Also, when you generate Public-Private key pair, use a strong passphrase to encrypt the private key. This way whenever you use your private key to ssh into a remote host, you would need the passphrase to decrypt the private key.

Disable empty passwords

System administrators can create users with blank passwords. This can help attackers gain easy access to system. Thus, the best way is to disable remote login for such users.

PermitEmptyPasswords no

Configure idle login timeout interval

SSH allows you to configure idle timeout for current user. Once the time is elapsed, the user will be automatically logged out. ClientAliveInterval determines how long (in seconds) the server will wait for idle ssh connection before it sends a null packet to client to respond. ClientAliveMaxCount determines how many times the server will send null packet to client, before dropping the connection.

ClientAliveInterval 120
ClientAliveCountMax 2

Disable SSH forwarding

Port forwarding allows a host to act as a proxy for another remote host. This usually is not required, unless there is a very specific need. Why is this a threat? Read here. Also, if you server is running a GUI, when you access the remote server via SSH, you don’t need the GUI, so disabling X11 forwarding is the right thing to do. X11Forwarding wasn’t built with security as priority.

AllowTcpForwarding no
X11Forwarding no

In case you need to allow TCP forwarding for any particular user, you can make exception in the configuration.

AllowTcpForwarding no
Match User <exceptional-user>
AllowTcpForwarding yes

Limit ssh access from white-listed IPs only

By default SSH will accept incoming connection from any host. To restrict this, you can provide a set of white-listed IPs which are allowed to make SSH connection. You can specify multiple IPs to white-list

ListenAddress <IP-Address-1>
ListenAddress <IP-Address-2>

Limit specific users / groups to remote login via SSH

There can be several users and groups on a Linux system, but not all of them need to SSH remotely. You can control this by configuring AllowGroups and AllowUsers. Mind that when AllowUsers is specified, it takes precedence over AllowGroups

AllowUsers <user-1> <user-2>….<user-n>
AllowGroups <group-1> <group-2>…<group-n>

Limit maximum authentication attempts

To protect against brute-force attacks on password based login, limit the maximum number of attempts allowed. Also, enable logging for failed login attempts.

MaxAuthTries <max-authentication-try-count>

MaxAuthTries will also count when you use PPK authentication for login. To enforce password based authentication from client use the following options

ssh -o PreferredAuthentications=password -o PubKeyAuthentication=no <remote-user>@<remote-host>

Hide last login information

Though not particular in terms of enhancing security, it is advised to disable printing information about last login on the system, to reveal as less information as possible.

PrintLastLog no

Disable .Rhosts

On the remote host, file ~/.rhosts for any user is equivalent to the file /etc/hosts.equiv or /etc/shosts.equiv, which contains a list of combination of user and host. The user specified in the file is granted remote login access without any password. This becomes a security challenge because, even though file /etc/hosts.equiv is modifiable by root, any user can create a .rhosts file in their home directory and gain remote access without permission from the root user.

IgnoreRhosts yes

Disable host based authentication

Host based authentication allows a host to authenticate a user on its behalf. This means that all users or a subset of users from a host can be authenticated just because they are originating the SSH connection from a trusted host. In general, it is advisable to so only in closed network, otherwise disable the setting.

HostbasedAuthentication no

Block SSH brute force attack using third-party tools

There are several tools available which can help you prevent brute-force attack on SSH, such as SSHGuard, Fail2Ban, DenyHosts etc.

Chroot OpenSSH to limit users to their home directory

OpenSSH has provision to limit the access to a particular directory only for a particular remotely logged in user. Setting this would confine the user to a particular directory and its content. For more details, see — https://www.tecmint.com/restrict-ssh-user-to-directory-using-chrooted-jail/

Match User <restricted-user>
ChrootDirectory <restricted-user-directory>

Enable multi-factor authentication

Until now we saw that a user is passed through only on authentication process. This can be hardened by adding more authentication process. Such as configuring using Google Authenticator PAM for second authentication, such as SMS based OTP. Alternately, you can use Mobile apps such as Google Authenticator or FreeOTP to generate the OTP.

For more details, see — https://www.digitalocean.com/community/tutorials/how-to-set-up-multi-factor-authentication-for-ssh-on-ubuntu-16-04

Set a custom warning banner up login

This one does nothing particular to enhance security, but it warns users of the legal consequences if they try to do anything malicious. To display the banner of warning, set the following parameter.

Banner <path-to-warning-message-file>

Enable DNS hostname checking

By default SSH server can check if the remote host maps back to the same combination of IP and hostname. Though this does not enhances security very much, unless rhost based authentication is used.

UseDNS yes
IgnoreRHosts no

Change hostkey preferences

OpenSSH supports various key exchange algorithms, ciphers and message authentication code. The remote and local host arrive on a common set of algorithms before proceeding with key exchange. Not all key exchange algorithms are great and must be disabled.

KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256

For more details see — https://stribika.github.io/2015/01/04/secure-secure-shell.html

Regenerate Moduli

The file /etc/ssh/moduli contains list of prime numbers and generators used by SSH daemon in Diffie-Hellman Group Exchange key exchange process for encrypting communication between remote and local host. The default values in the file /etc/ssh/moduli may not be unique. So its a good idea to regenerate them for better randomness. To create new moduli file, execute the following set of commands in specified order

ssh-keygen -G /etc/ssh/moduli.all -b 4096
ssh-keygen -T /etc/ssh/moduli.safe -f /etc/ssh/moduli.all
mv /etc/ssh/moduli.safe /etc/ssh/moduli
rm /etc/ssh/moduli.all
// Execute the following commands to retain keys of length 2048 or more
awk '$5 >= 2048' /etc/ssh/moduli > /etc/ssh/moduli.safe
mv /etc/ssh/moduli.safe /etc/ssh/moduli

For more details see — https://entropux.net/article/openssh-moduli/

Use privilege separation

It is usually safer to run a process as non-root user. The same applies for SSH daemon as well. By enabling this flag, the SSH daemon starts with pretty small footprint as root user and drops privileges as soon as possible to run as unprivileged process.

UsePrivilegeSeparation yes

Use port knocking to block brute-force attacks

Port knocking is a stealth mode technique to hide the open ports on a remote host. This basically requires user to make connections to a series of closed ports on the remote host in a particular order, before the firewall opens up the actual port. Similarly, the closed ports need to knocked in the reverse order to close the actual port. This prevents the port-scanning tools from discovering the open ports on the remote host. This requires installing knockd and iptables on the remote host. For more details see — https://www.howtoforge.com/tutorial/how-to-use-port-knocking-to-hide-the-ssh-port-from-attackers-on-ubuntu/

Hash known hosts

This one is for securing the client host. On the client, enable hashing of known hosts, so that in case of compromise, least information is leaked to attacker. This setting can be changed in /etc/ssh/ssh_config.

Given that PPK has been setup between a client and remote host, when the client initiates a SSH connection to remote host, the remote host responds with the public key of the client. This allows client to verify that the server is correct one and not rogue. Client stores information about the known servers in file at path ~/.ssh/known_hosts. The known hosts information can also be stored globally for all users in file — /etc/ssh/known_hosts.

HashKnownHosts yes

Keep your system updated to stay ahead in security

Clean up the revoked keys to keep the access clean and updated

After making the change, you need to restart the SSH daemon to pickup the new configuration. But before doing so, test the new configuration by executing the command

sshd -t

I have looked up various pages on internet to gather all these information. Links to pages have been added at relevant points in this article. That’s all folks.

--

--