Friday, February 28, 2025

How to Secure SSH in Linux (SSH Hardening)

 

How to Secure SSH in Linux (SSH Hardening)

The Secure Shell (SSH) protocol is one of the essential tools for Linux system administrators. This tool allows you to manage Linux servers from the comfort of your office or even from the comfort of your home. After all, this method is much better than having to put on your jacket and go through security barriers to enter the cold server room. The word secure in Secure Shell means that everything you type or transmit is encrypted. This eliminates the possibility that someone could obtain sensitive data by connecting to your network through a sniffer.

At this point in your Linux career, you need to know how to use Secure Shell or SSH to log in remotely and transfer files remotely. What you may not know is that the default configuration of SSH is actually relatively insecure. In this chapter, we'll explore ways to boost the default configuration. We'll explore how to use stronger encryption algorithms than the default, how to set up passwordless authentication, and how to set up a prison for Secure File Transfer Protocol (SFTP) users. As an added bonus, we'll explore how to scan SSH servers for vulnerable configurations and how to share a remote directory via Secure Shell Filesystem (SSHFS).

In this chapter, we will explore the following topics:

  • Ensure that SSH protocol version 1 is disabled
  • Create and manage keys to log in without the need for a password
  • Disable root user login
  • Disable login with username and password
  • Configuring Secure Shell with Strong Encryption Algorithms
  • Setting Global Encryption Policies in RHEL 8/CentOS 8
  • FIPS Mode in CentOS 8/Red Hat 8
  • Configure more accurate logging
  • Access Control with Whitelisting and TCP Wrappers
  • Configuring automatic checkouts and security banners
  • Various other security settings
  • Configuring Different Settings for Different Hosts
  • Configure different settings for different users and groups
  • Scan an SSH server
  • Setting up a chroot environment for SFTP users
  • Setting up shared directories with SSHFS
  • Remote connection from Windows desktops

So if you're ready, let's get started.

Ensure that SSH protocol version 1 is disabled

The SSH version 1 protocol, which is the original SSH protocol, has serious flaws and should never be used. This protocol is still available on most Linux distributions, but thankfully it's disabled by default. However, let's say you open your file and see this line:/etc/ssh/sshd_config

Protocol 1

Or you might see:

Protocol 1, 2

If you see this, you are facing a problem.

The MAN Help page for files in Ubuntu says that version 1 of the protocol is still available for use with older devices. However, if you still have devices with such versions, you should seriously consider upgrading them. As Linux distributions are updated, you'll see that the SSH protocol version 1 is gradually being completely removed, as was the case with Red Hat and CentOS version 7.4.sshd_config

Creating and Managing Keys for Passwordless Login

SSH is an excellent set of tools used to communicate with remote servers. You can use the SSH component to enter the command line of a device remotely, and you can also use it to transfer files securely. The default way to use any of these components is to use a person's normal Linux account username and password. So, logging into the remote device from my OpenSUSE device terminal would look something like this:scpsftp

donnie@linux-0ro8:~> ssh donnie@192.168.0.8
donnie@192.168.0.8's password:

While it's true that usernames and passwords are transmitted cryptographically over the network, making it harder for attackers to penetrate, it's still not the most secure way to do so. The problem is that the attackers have access to automated tools that can carry out password brute-force attacks against an SSH server. Botnets, such as Hail Mary Cloud, perform continuous scans across the internet to find servers with SSH-enabled.

If a botnet detects that servers are allowing access to SSH via username and password, it initiates a brute-force password attack. Unfortunately, such attacks have been successful several times, especially when server operators allow the root user to log in via SSH.

This old article provides more information about the Hail Mary Cloud botnet: Article Link.

In the next section, we will look at two ways to help prevent these types of attacks:

  • Enabling SSH Login via Public Key Exchange
  • Disable root user login via SSH

Now let's create a few keys.

Creating an SSH Key Set for a User

Each user has the option to create their own set of private and public keys. It doesn't matter if the user's client device is running Linux, macOS, Cygwin on Windows, or Bash Shell for Windows. In all these cases, the process of doing the work is exactly the same.

Creating SSH keys for users

There are many different types of keys you can create, and RSA keys with a length of 2048 bits are usually used as the default. Until not so long, RSA keys with a length of 2048 bits were considered strong enough for the foreseeable future. But now, the most recent guidance from the U.S. National Institute of Standards and Technology (NIST) recommends using an RSA key with a minimum of 3072 bits or an elliptical curve digital signature algorithm (ECDSA) key with a minimum of 384 bits. (Sometimes these ECDSA keys are also known as P-384). The reason for this recommendation is that they want to prepare us for quantum computing, which would be so powerful that it would render any weaker cryptographic algorithm obsolete. Of course, quantum computing is not yet operational, and so far it seems like it's always something that will come ten years from now, no matter what year we're in. But even if we assume that we ignore the problem of quantum computing, we must acknowledge that our current non-quantum computers are still getting more and more powerful. So, it's still not a bad idea to start using stronger crypto standards.

To view the list of cryptographic algorithms recommended by NIST and the proposed key lengths, you can visit this link.

For these few demos, let's switch to an Ubuntu 18.04 client. To create an RSA key pair with a length of 3072 bits, simply enter the following command:

donnie@ubuntu1804-1:~$ ssh-keygen -t rsa -b 3072

Here, we'll use the option to specify if we want to generate an RSA key, and we'll use the option to determine the bit length. When you are asked to enter the location and name of the keys, I just hit Enter to select the default values. You can leave the private key without a passphrase, but this method is not recommended.-t-b

Note that if you choose a different name for your key files, you'll need to enter the full path of the files to make everything work properly. For example, in my case, I have to specify the path of the donnie_rsa keys./home/donnie/.ssh/donnie_rsa

You will see your new keys in the .ssh directory:

donnie@ubuntu1804-1:~$ ls -l .ssh
total 8
-rw------- 1 donnie donnie 2546 Aug 28 15:23 id_rsa
-rw-r--r-- 1 donnie donnie 573 Aug 28 15:23 id_rsa.pub
donnie@ubuntu1804-1:~$

Here:

  • id_rsa It's your private key.
  • id_rsa.pub is your public key.

As you can see, id_rsa has limited access(), which means that only you (the donnie user) can read and write it, which provides decent security. The public key (id_rsa.pub) is readable for others to easily use on other servers for SSH authentication.-rw-------

Note that if you have created the default 2048-bit keys, the names will be similar.

  • id_rsa key is your private key, and only you can read and write it.
  • id_rsa.pub key is your public key that should be readable to everyone.

For ECDSA keys, the default length is 256 bits. If you decide to use ECDSA instead of RSA, enter the following command to create a strong 384-bit key:

donnie@ubuntu1804-1:~$ ssh-keygen -t ecdsa -b 384

Either way, when you look at the .ssh directory, you'll see that the names of the ECDSA keys are different from the RSA keys:

donnie@ubuntu1804-1:~$ ls -l .ssh
total 8
-rw------- 1 donnie donnie 379 May 27 17:43 id_ecdsa
-rw-r--r-- 1 donnie donnie 225 May 27 17:43 id_ecdsa.pub
donnie@ubuntu1804-1:~$

The beauty of elliptic curve algorithms is that their seemingly short key lengths are just as safe as long RSA keys. Even the largest ECDSA keys require less computing power than RSA keys. The maximum key length you can use with ECDSA is 521 bits. (Yes, you read that right. 521 bits, not 524 bits.)

So you may ask, why not only use 521-bit keys? The main reason is that 521-bit keys are not recommended by NIST. The reason for this is the concern of padding attacks, which can allow attackers to crack your encryption and steal your data.

If you take a look at the MAN's guide page for, you'll notice that you can create an Ed25519-type key, sometimes referred to as the curve25519. This variant is not on the list of algorithms recommended by NIST, but there are a few reasons why some people prefer to use it.ssh-keygen

The first reason is that RSA and DSA can disclose private key data when creating signatures if the operating system's random number generator is in trouble. ED25519 does not require the generation of random numbers when creating signatures, so it is resistant to this problem. Additionally, Ed25519 is coded to be much less vulnerable to side-channel attacks. (Side-channel attacks occur when someone tries to exploit vulnerabilities in the underlying operating system instead of a cryptographic algorithm.)

The second reason why some people prefer Ed25519 is precisely because it is not on the NIST list. These people are people who, rightly or wrongly, do not trust the recommendations of government agencies.

A few years ago, earlier this century, there was a scandal about the Dual Elliptic Curve Deterministic Random Bit Generator (Dual_EC_DRBG). It was a random number generator that was to be designed for use in elliptical curve cryptography. The problem was that initially, some independent researchers found that the manufacturer had the capabilities to create back doors, which anyone who was aware of could import. Interestingly, the only people who should have known about this capability were those who worked for the U.S. National Security Agency (NSA). At the request of the NSANIST placed Dual_EC_DRBG on its list of recommended algorithms, and this situation continued until April 2014, when it was finally removed.

For more details, you can visit the following links:

To read more details about ED25519, you can visit the following link:

For Ed25519, there is only one key size, which is 256 bits. So, to create a curve25519 key, just use the following command:

donnie@ubuntu1804-1:~$ ssh-keygen -t ed25519

Here are the keys I've created:

donnie@ubuntu1804-1:~$ ls -l .ssh
total 8
-rw------- 1 donnie donnie 464 May 27 20:11 id_ed25519
-rw-r--r-- 1 donnie donnie 101 May 27 20:11 id_ed25519.pub
donnie@ubuntu1804-1:~$

However, ED25519 has some potential disadvantages:

1. Lack of support by legacy SSH clients: However, this issue shouldn't be an issue when everyone on the team is using new operating systems and up-to-date SSH clients.

2. Only one fixed key length: This key is equivalent to 256-bit elliptic curve or 3,000-bit RSA encryption algorithms. So it may not be as good for foresight as some of the other algorithms we've covered.

3. Non-compliance with NIST requirements: If your organization must comply with NIST recommendations, you will not be able to use this key.

Finally, another type of key that can still be generated by ssh-keygen is the old DSA key. But it is not recommended to use this type. The DSA algorithm is outdated, fragile, and highly insecure by modern standards. So, when you get to the DSA, just say no.

Transferring the public key to the remote server allows the server to identify both me and my client's device. Before I can transfer my public key to the remote server, I must first add the private key to my session keyring. This requires two instructions. (One command runs ssh-agent, and the other adds the private key to the keyring):

donnie@ubuntu1804-1:~$ exec /usr/bin/ssh-agent $SHELL
donnie@ubuntu1804-1:~$ ssh-add
Enter passphrase for /home/donnie/.ssh/id_rsa:
Identity added: /home/donnie/.ssh/id_rsa (/home/donnie/.ssh/id_rsa)
Identity added: /home/donnie/.ssh/id_ecdsa (/home/donnie/.ssh/id_ecdsa)
Identity added: /home/donnie/.ssh/id_ed25519 (donnie@ubuntu1804-1)
donnie@ubuntu1804-1:~$

Finally, I can move my public keys to the CentOS server, which is located at 192.168.0.8:

donnie@ubuntu1804-1:~$ ssh-copy-id donnie@192.168.0.8
The authenticity of host '192.168.0.8 (192.168.0.8)' can't be established.
ECDSA key fingerprint is
SHA256:jUVyJDJl2AHJgyrqLudOWx4YUtbUxD88tv5oKeFtfXk.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to
filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 3 key(s) remain to be installed -- if you are
prompted now it is to install the new keys
donnie@192.168.0.8's password:
Number of key(s) added: 3
Now try logging into the machine, with: "ssh 'donnie@192.168.0.8'"
and check to make sure that only the key(s) you wanted were added.
donnie@ubuntu1804-1:~$

With this, your public keys have been added to the destination server, and you can log in to the server securely. Usually, you only make a pair of keys of the type you have chosen. As you can see here, I've made three pairs of keys, one pair of each type. All three private keys have been added to my session keyring, and all three public keys have been moved to the remote server. The next time I log in, I'll use Key Exchange and won't need to enter a password:

donnie@ubuntu1804-1:~$ ssh donnie@192.168.0.8
Last login: Wed Aug 28 13:43:50 2019 from 192.168.0.225
[donnie@localhost ~]$

As I said earlier, usually you only make one pair of keys for each device. However, there are exceptions to this rule. Some administrators prefer to use a different key pair for each server they manage, rather than using the same key pair for all servers. A convenient way to do this is to construct keys with file names that match the hostnames of the respective servers. You can then use the -i option to specify the key pair you want to use.

In this example, I only have one server, but I have different keys for it. Suppose I prefer to use the Ed25519 keys:

donnie@ubuntu1804-1:~$ ssh -i ~/.ssh/id_ed25519 donnie@192.168.0.8
Last login: Wed Aug 28 15:58:26 2019 from 192.168.0.3
[donnie@localhost ~]$

Now, you may be asking, if I log in without entering a password, how is it secure? The answer is that when I close the terminal window of my client device that I used to log in, the private key will be removed from my session keyring. When I open a new terminal and want to log in to the remote server, I see this message:

donnie@ubuntu1804-1:~$ ssh donnie@192.168.0.8
Enter passphrase for key '/home/donnie/.ssh/id_rsa':
Last login: Wed Aug 28 16:00:33 2019 from 192.168.0.3
[donnie@localhost ~]$

So every time I log in to this server, I have to enter my private key password (unless I add it back to the session keyring with the two commands I showed earlier)...

Creating and transferring SSH keys

 

Creating and transferring SSH keys

In this workshop, you will use a virtual machine (VM) as a client and another virtual machine as a server. If you're using a Windows hosting machine, you can use Cygwin, PowerShell, or the built-in Windows Bash shell as a client. (Note that PowerShell and Windows Bash Shell store keys in different locations.) If you're using a Mac or Linux hosting machine, you can use the native command-line terminal of the same machine as the client. Either way, the process will be the same. For a virtual server machine, use Ubuntu or CentOS 7. This process works the same way in CentOS 8. However, we'll be using this virtual machine for future workshops, and CentOS 8 has some special points that we'll get to later. Let's get started:

  1. On the client machine, create a 384-bit elliptical curve key pair. Specify the default name and location of the file and set a password for it:
    ssh-keygen -t ecdsa -b 384
    
  2. View the keys and check the permissions settings:
    ls -l ./ssh
    
  3. Add your private key to your meeting keyring. When prompted, enter the password:
    exec /usr/bin/ssh-agent $SHELL
    ssh-add
    
  4. Move the public key to the server's virtual machine. When prompted, enter your account password on the server's virtual machine (replace your username and IP address in the following command):
    ssh-copy-id donnie@192.168.0.7
    
  5. Log in to the virtual machine server as always:
    ssh donnie@192.168.0.7
    
  6. View the file created on the server: authorized_keys
    ls -l .ssh
    cat .ssh/authorized_keys
    
  7. Exit the server's virtual machine and close the terminal window on the client machine. Open a new terminal window and try logging in to the server again. This time, you should be asked to enter your private key password.
  8. Log out of the server virtual machine again and add your private key to the client's machine session keyring. When prompted, enter your private key password:
    exec /usr/bin/ssh-agent $SHELL
    ssh-add
    

    As long as you keep this terminal window open on the client's machine, you can log in to the server's virtual machine as many times as you want without entering a password. However, when you close the terminal window, your private key will be removed from your session keyring.

  9. Keep the server virtual machine, as we will work with it in the future.

You've reached the end of the workshop – congratulations!
What we did here is good, but it's still not enough. One disadvantage is that if you switch to another client machine, you can still use the normal username/password authentication method to log in. This is not a problem, we will fix it in a few moments.

Disabling root user login

A few years ago, there was a fairly well-known case where attackers were able to install malware on a number of Linux servers somewhere in Southeast Asia. There were three reasons why it was so easy for attackers:

  1. Servers connected to the Internet were configured to use username/password authentication for SSH.
  2. The root user was allowed to log in via SSH.
  3. Users' passwords, including the root user password, were very weak.

All of this made it easy for the malware to enter the system with a brute-force attack.

Different distributions have different default settings for root user login. In the file on your CentOS machine, you'll see this line:/etc/ssh/sshd_config

#PermitRootLogin yes

Unlike most configuration files, they define the lines commented in the default settings for the Secure Shell. So this line indicates that the root user has been allowed to log in via SSH. To change these settings, I'll remove the comment watermark and change the value to:sshd_configno

PermitRootLogin no

To apply this change, I'm restarting the SSH, known as in CentOS. In Ubuntu, this is called:sshdssh

sudo systemctl restart sshd

On the Ubuntu machine, the default settings are slightly different:

PermitRootLogin prohibit-password

This means that the root user is allowed to log in, but only through public key exchange. This setting is probably safe for most cases, if you really need to allow the root user to log in. But in most cases, you'll want to ask admin users to log in with their regular account and use it for admin needs. So, in most cases, you'll still want to change this setting.sudono

Note that if you implement a Linux instance on a cloud service like Rackspace or Vultr, the service owners will require you to sign in with a root account. The first thing you need to do is create your regular account, log in with it, then disable the root account and disable root login in . Microsoft Azure is an exception to this rule because it automatically creates an unauthorized user account for you.sshd_config

Disable login with username/password

This is what you should only do after you set up a key exchange with your client. Otherwise, your client will not be able to perform remote login.

Hands-on Workshop – Disabling Root Login and Password Authentication

For this workshop, use the same virtual machine server that you used for the previous workshop. Let's get started:

  1. On the Ubuntu or CentOS server virtual machine, look for this line in the file: sshd_config
    #PasswordAuthentication yes
    
  2. Remove the comment watermark, change the parameter value to and restart SSH. The line should be changed as follows: no
    PasswordAuthentication no
    

    Now, when your network bots scan the system, they will see that a brute-force SSH attack using a password is useless. As a result, they leave and leave you alone.

  3. Look for one of these two lines, depending on whether your server is Ubuntu or CentOS:
    #PermitRootLogin yes
    #PermitRootLogin prohibit-password
    

    Uncomment the line and change it to the following way:

    PermitRootLogin no
    
  4. Restart SSH to make new changes. In Ubuntu, you can do this as follows:
    sudo systemctl restart ssh
    

    In CentOS, this is done in the following way:

    sudo systemctl restart sshd
    
  5. Try logging into the virtual machine server through the client you used in the previous workshop.
  6. Try logging into the virtual machine server from another client where you didn't create a key pair. (You must not be able to log in.)
  7. As mentioned earlier, keep the server virtual machine, as we will be working with it more in the future.

Now that we've explored how to create a private/public key pair on the client side and how to transfer the public key to the server, let's talk about the type of algorithms that SSH uses. After that, we'll move on to how to disable some of the older and weaker algorithms.

Configuring Secure Shell with Strong Encryption Algorithms

As I mentioned earlier, NIST's set of recommendations, the CNSA Suite, involves the use of stronger algorithms and longer keys than we previously needed. Here are the new recommendations in this table:

AlgorithmUse
RSA, 3,072 bits or moreKey Establishment and Digital Signature
Diffie-Hellman (DH), 3,072 bits or moreKey Establishment
ECDH with NIST P-384Key Establishment
ECDSA with NIST P-384Digital Signature
SHA-384Integrity
AES-256Privacy

In some other publications, you may see the NIST Suite B standard as the recommended standard for cryptographic algorithms. Suite B is an old standard that has been replaced by the CNSA Suite. Another cryptographic standard you may work with is the Federal Information Processing Standard (FIPS), which is also published by the US government. The current version is FIPS 140-2, last revised in December 2002. FIPS 140-3, which was finalized on September 22, 2019, will eventually become the new standard. U.S. government agencies that are subject to FIPS compliance have already been ordered to gradually transition to FIPS 140-3.

Understanding SSH Cryptographic Algorithms

SSH works with a combination of symmetric and asymmetric cryptography, similar to how Transport Layer Security (TLS) works. The SSH client initiates the process by using the public key method to establish an asymmetric session with the SSH server. Once this session is created, the two devices can agree on a secret code and exchange it, which they use to set up a symmetric session. (As we've already seen in TLS, we want to use symmetric cryptography for performance reasons, but we need an asymmetric session to make the secret key exchange happen.) To accomplish this process, we need four sets of cryptographic algorithms, which we will configure on the server side. These include:

  1. Ciphers: These are symmetric algorithms that encrypt the data that is exchanged between the client and the server.
  2. HostKeyAlgorithms: This is a list of host key types that the server can use.
  3. KexAlgorithms: These are the algorithms that the server can use to perform symmetric key exchanges.
  4. MAC (Message Authentication Codes): These are hashing algorithms that sign cryptographic data in transit. This will ensure the integrity of the data and let you know if someone has tampered with your data or not.

The best way to familiarize yourself with these is to view the MAN file page:sshd_config

man sshd_config

I can use any virtual machine to display these. Currently, I'm using CentOS 7 unless I mention otherwise. (Lists of default and available algorithms will vary for different Linux distributions and versions.)

Lab Hands-on – Installing and Using ssh_scan

In this section, we will use the ssh_scan tool to scan for active SSH algorithms. We will follow the step-by-step steps of installing and using this tool as follows:

Installation and use of ssh_scan:

  1. Installation of Required Packages (Ruby and gem): ssh_scan is written in Ruby and presented as a Ruby gem. So, we need to install Ruby and gem first. Depending on your Linux distribution, enter the appropriate command:

    • For Ubuntu:
      sudo apt update
      sudo apt install ruby gem
      
    • For CentOS 7:
      sudo yum install ruby gem
      
    • For CentOS 8:
      sudo dnf install ruby gem
      
  2. Installing ssh_scan gem: Now that we have installed Ruby and gem, we need to install the ssh_scan package. To do this, enter the following command:
    sudo gem install ssh_scan
    
  3. Creating a symlink in CentOS: In most distributions, ssh_scan is installed on the way. But in CentOS, if you use it to call the command in this directory, the system won't find it, even if the path is in the root user settings. So, the solution to this problem is to create an iconic link to. Just do it in CentOS/usr/local/bin/sudoPATH/usr/bin/
    sudo ln -s /usr/local/bin/ssh_scan /usr/bin/ssh_scan
    
  4. View ssh_scan Command Options: The ssh_scan tool doesn't have a MAN page, but you can see a list of its command options using the following command:
    sudo ssh_scan -h
    

    This command will show you a guide to using the ssh_scan.

  1. Scan the VM server you built and configured in previous tests.
    Replace your IP address with the one I used here. Note that the output of the page is in JSON format. Also, note that even if you haven't created the key pair on your scanner, the scan will still work on machines where username/password authentication is disabled (but of course you won't be able to log in from the scanner):
sudo ssh_scan -t 192.168.0.7
  1. Repeat the scan, but save the output to .json file this time, like this:
sudo ssh_scan -t 192.168.0.7 -o ssh_scan-7.json
  1. You can open the JSON file in a normal text editor or turntable, but it's best to open it in your web browser.
    Transfer the file to a device that has a desktop interface and open it in your preferred web browser. You should see something like this:

    ssh scan JSON
  2. You will see a complete list of all the active algorithms. At the bottom, you'll see recommendations on which algorithms you should enable or disable. Since ssh_scan is a project of the Mozilla Foundation, it uses Mozilla's own recommendations as a policy guide. These are not the same standards that organizations like NIST recommend. Therefore, you should compare your results with standards that are applicable to your condition, such as the CNSA NIST standard, to ensure that you have enabled or disabled the right things.
  3. On your host machine or a VM with a desktop interface, visit the Shodan website at https://www.shodan.io.
    Enter the word ssh in the search window and see a list of SSH servers that are exposed to the internet. Click on different IP addresses to find the SSH server that is not running on the default port 22. See a list of active algorithms for that device.
  4. Scan the device, using the -p switch to scan different ports, like this:
sudo ssh_scan -t 178.60.214.30 -p 222 -o ssh_scan-178-60-214-30.json

Note that in addition to the list of active algorithms you saw on Shodan, you now have a list of weak algorithms that the owner of this device needs to disable.

  1. Keep this scanner and this VM server handy, as we will be using them again after disabling some algorithms