Quick Links

Secure your Linux system's SSH connection to protect your system and data. System administrators and home users alike need to harden and secure internet-facing computers, but SSH can be complicated. Here are ten easy quick-wins to help protect your SSH server.

SSH Security Basics

SSH stands for Secure Shell. The name "SSH" is used interchangeably to mean either the SSH protocol itself or the software tools that allow system administrators and users to make secure connections to remote computers using that protocol.

The SSH protocol is an encrypted protocol designed to give a secure connection over an insecure network, such as the internet. SSH in Linux is built on a portable version of the OpenSSH project. It is implemented in a classic client-server model, with an SSH server accepting connections from SSH clients. The client is used to connect to the server and to display the session to the remote user. The server accepts the connection and executes the session.

In its default configuration, an SSH server will listen for incoming connections on Transmission Control Protocol (TCP) port 22. Because this is a standardized, well-known port, it is a target for threat actors and malicious bots.

Threat actors launch bots that scan a range of IP addresses looking for open ports. The ports are then probed to see if there are vulnerabilities that can be exploited. Thinking, "I'm safe, there are bigger and better targets than me for the bad guys to aim at," is false reasoning. The bots aren't selecting targets based on any merit; they're methodically looking for systems they can breach.

You nominate yourself as a victim if you haven't secured your system.

Security Friction

Security friction is the irritation---of whatever degree---that users and others will experience when you implement security measures. We've got long memories and can remember introducing new users to a computer system, and hearing them ask in a horrified voice whether they really had to enter a password every time they logged in to the mainframe. That---to them---was security friction.

(Incidentally, the invention of the password is credited to Fernando J. Corbató, another figure in the pantheon of computer scientists whose combined work contributed to the circumstances that led to the birth of Unix.)

Introducing security measures usually involves some form of friction for someone. Business owners have to pay for it. The computer users may have to change their familiar practices, or remember another set of authentication details, or add extra steps to connect successfully. The system administrators will have additional work to do to implement and maintain the new security measures.

Hardening and locking down a Linux or Unix-like operating system can get very involved, very quickly. What we're presenting here is a set of easy to implement steps that will improve the security of your computer without the need for third-party applications and without digging through your firewall.

These steps aren't the final word in SSH security, but they'll move you a long way forward from the default settings, and without too much friction.

Use SSH Protocol Version 2

In 2006, the SSH protocol was updated from version 1 to version 2. It was a significant upgrade. There were so many changes and improvements, especially around encryption and security, that version 2 is not backward compatible with version 1. To prevent connections from version 1 clients, you can stipulate that your computer will only accept connections from version 2 clients.

To do so, edit the

        /etc/ssh/sshd_config
    

file. We'll be doing this a lot throughout this article. Whenever you need to edit this file, this is the command to use:

sudo gedit /etc/ssh/sshd_config

sudo gedit /etc/ssh/sshd_config in a terminal window

Add the line:

Protocol 2

sshd_config in gedit with the edits highlighted

And save the file. We're going to restart the SSH daemon process. Again, we'll be doing this a lot throughout this article. This is the command to use in each case:

sudo systemctl restart sshd

sudo gedit /etc/ssh/sshd_config in a terminal window

Let's check that our new setting is in force. We'll hop over to a different machine and try to SSH onto our test machine. And we'll use the -1 (protocol 1) option to force the ssh command to use protocol version 1.

ssh -1 dave@howtogeek.local

ssh -1 dave@howtogeek.local in a terminal window

Great, our connection request is rejected. Let's ensure we can still connect with protocol 2. We'll use the -2 (protocol 2) option to prove the fact.

ssh -2 dave@howtogeek.local

ssh -2 dave'howtogeek.local in a terminal window

The fact that the SSH server is requesting our password is a positive indication that the connection has been made and you are interacting with the server. Actually, because modern SSH clients will default to using protocol 2, we don't need to specify protocol 2 as long as our client is up to date.

ssh dave@howtogeek.local

ssh dave@howtogeek.local in a terminal window

And our connection is accepted. So it is only the weaker and less secure protocol 1 connections that are being rejected.

Avoid Port 22

Port 22 is the standard port for SSH connections. If you use a different port, it adds a little bit of security through obscurity to your system. Security through obscurity is never considered a true security measure, and I have railed against it in other articles. In fact, some of the smarter attack bots probe all open ports and determine which service they are carrying, rather than relying on a simple look-up list of ports and assuming they provide the usual services. But using a non-standard port can help with lowering the noise and bad traffic on port 22.

To configure a non-standard port, edit your SSH configuration file:

sudo gedit /etc/ssh/sshd_config

SSH config file in gedit with edits highlighted

Remove the hash # from the start of the "Port" line and replace the "22" with the port number of your choice.  Save your configuration file and restart the SSH daemon:

sudo systemctl restart sshd

Let's see what effect that has had. Over on our other computer, we'll use the ssh command to connect to our server. The ssh command defaults to using port 22:

ssh dave@howtogeek.local

ssh dave@howtogeek.local in a terminal window

Our connection is refused. Let's try again and specify port 470, using the -p (port) option:

ssh -p 479 dave@howtogeek.local

ssh -p  479 dave@howtogeek.local in a terminal window

Our connection is accepted.

Filter Connections Using TCP Wrappers

TCP Wrappers is an easy to understand access control list. It allows you to exclude and permit connections based on characteristics of the connection request, such as IP address or hostname. TCP wrappers should be used in conjunction with, and not instead of, a properly configured firewall.  In our specific scenario, we can tighten things up considerably by using TCP wrappers.

TCP wrappers was already installed on the Ubuntu 18.04 LTS machine used to research this article. It had to be installed on Manjaro 18.10 and Fedora 30.

To install on Fedora, use this command:

sudo yum install tcp_wrappers

sudo yum install tcp_wrappers in a terminal window

To install on Manjaro, use this command:

sudo pacman -Syu tcp-wrappers

sudo pacman -Syu tcp-wrappers in a terminal window

There are two files involved. One holds the allowed list, and the other holds the denied list. Edit the deny list using:

sudo gedit /etc/hosts.deny

sudo gedit /etc/hosts.deny in a terminal window

This will open the gedit editor with the deny file loaded in it.

hosts.deny file loaded into gedit

You need to add the line:

ALL : ALL

And save the file. That blocks all access that hasn't been authorized. We now need to authorize the connections you wish to accept. To do that, you need to edit the allow file:

sudo gedit /etc/hosts.allow

sudo gedit /etc/hosts.allow in a terminal window

This will open the gedit editor with the allow file loaded in it.

hosts.allow file loaded in gedit with edits highlightsd

We've added in the SSH daemon name, SSHD,  and the IP address of the computer we're going to allow to make a connection. Save the file, and let's see if the restrictions and permissions are in force.

First, we'll try to connect from a computer that isn't in the hosts.allow file:

SSH connection refused by TCP wrappers

The connection is refused.  We'll now try to connect from the machine at IP address 192.168.4.23:

SSH connection permitted by TCP wrappers

Our connection is accepted.

Our example here is a bit brutal---only a single computer can connect. TCP wrappers is quite versatile and more flexible than this. It supports hostnames, wildcards, and subnet masks to accept connections from ranges of IP addresses. You are encouraged to check out the man page.

Reject Connection Requests With No Passwords

Although it is a bad practice, a Linux system administrator can create a user account with no password. That means remote connection requests from that account will have no password to check against. Those connections will be accepted but unauthenticated.

The default settings for SSH accept connection requests without passwords.  We can change that very easily, and ensure all connections are authenticated.

We need to edit your SSH configuration file:

sudo gedit /etc/ssh/sshd_config

SSH config file loaded in gedit with the edits highlgihted

Scroll through the file until you see the line that reads with "#PermitEmptyPasswords no." Remove the hash # from the start of the line and save the file. Restart the SSH daemon:

sudo systemctl restart sshd

Use SSH Keys Instead of Passwords

SSH keys provide a secure means of logging into an SSH server. Passwords can be guessed, cracked, or brute-forced. SSH keys are not open to such types of attack.

When you generate SSH keys, you create a pair of keys. One is the public key, and the other is the private key. The public key is installed on the servers you wish to connect to. The private key, as the name would suggest, is kept secure on your own computer.

SSH keys allow you to make connections without a password that are---counterintuitively---more secure than connections that use password authentication.

When you make a connection request, the remote computer uses its copy of your public key to create an encrypted message that is sent back to your computer. Because it was encrypted with your public key, your computer can unencrypt it with your private key.

Your computer then extracts some information from the message, notably the session ID, encrypts that, and sends it back to the server. If the server can decrypt it with its copy of your public key, and if the information inside the message matches what the server sent to you, your connection is confirmed to be coming from you.

Here, a connection is being made to the server at 192.168.4.11, by a user with SSH keys. Note that they are not prompted for a password.

ssh dave@192.168.4.11

SSH request being authenticated by SSH key in a terminal window

SSH keys merit an article all to themselves. Handily, we have one for you. Here's how to create and install SSH keys. Another fun fact: SSH keys are technically considered PEM files.

Related: How to Create and Install SSH Keys From the Linux Shell

Disable Password Authentication Altogether

Of course, the logical extension of using SSH keys is that if all remote users are forced to adopt them, you can turn off password authentication completely.

We need to edit your SSH configuration file:

sudo gedit /etc/ssh/sshd_config

gedit editor with the ssh config file loaded, and edits highlighted

Scroll through the file until you see the line that starts with "#PasswordAuthentication yes." Remove the hash # from the start of the line, change the "yes" to "no", and save the file. Restart the SSH daemon:

sudo systemctl restart sshd

Disable X11 Forwarding

X11 forwarding allows remote users to run graphical applications from your server over an SSH session. In the hands of a threat actor or malicious user, a GUI interface can make their malign purposes easier.

A standard mantra in cybersecurity is if you don't have a bonafide reason to have it turned on, turn it off.  We'll do so by editing your SSH config file:

sudo gedit /etc/ssh/sshd_config

gedit editor with the ssh config file loaded, and edits highlighted

Scroll through the file until you see the line that starts with "#X11Forwarding no." Remove the hash # from the start of the line and save the file. Restart the SSH daemon:

sudo systemctl restart sshd

Set an Idle Timeout Value

If there is an established SSH connection to your computer, and there has been no activity on it for a period of time, it could pose a security risk. There is a chance that the user has left their desk and is busy elsewhere. Anyone else who passes by their desk can sit down and start using their computer and, via SSH, your computer.

It's much safer to establish a timeout limit. The SSH connection will be dropped if the inactive period matches the time limit. Once more, we'll edit your SSH configuration file:

sudo gedit /etc/ssh/sshd_config

gedit editor with the SSH config file loaded and edits highlighted

Scroll through the file until you see the line that starts with "#ClientAliveInterval 0" Remove the hash # from the start of the line, change the digit 0 to your desired value. We've used 300 seconds, which is 5 minutes. Save the file, and restart the SSH daemon:

sudo systemctl restart sshd

Set a Limit For Password Attempts

Defining a limit on the number of authentication attempts can help thwart password guessing and brute-force attacks. After the designated number of authentication requests, the user will be disconnected from the SSH server. By default, there is no limit. But that is quickly remedied.

Again, we need edit your SSH configuration file:

sudo gedit /etc/ssh/sshd_config

gedit editor with the ssh config file loaded, and edits highlighted

Scroll through the file until you see the line that starts with "#MaxAuthTries 0". Remove the hash # from the start of the line, change the digit 0 to your desired value. We've used 3 here. Save the file when you made your changes and restart the SSH daemon:

sudo systemctl restart sshd

We can test this by attempting to connect and deliberately entering an incorrect password.

User being disconnected after two bad authentication attampts in a terminal window

Note that MaxAuthTries number seemed to be one more than the number of tries the user was permitted. After two bad attempts, our test user is disconnected. This was with MaxAuthTries set to three.

Disable Root Log Ins

It is bad practice to log in as root on your Linux computer. You should log in as a normal user and use sudo to perform actions that require root privileges. Even more so, you shouldn't allow root to log into your SSH server. Only regular users should be allowed to connect. If they need to perform an administrative task, they should use sudo too. If you're forced to allow a root user to log in, you can at least force them to use SSH keys.

For the final time, we're going to have to edit your SSH configuration file:

sudo gedit /etc/ssh/sshd_config

gedit editor with the ssh config file loaded, and edits highlighted

Scroll through the file until you see the line that starts with "#PermitRootLogin prohibit-password" Remove the hash # from the start of the line.

  • If you want to prevent root from logging in at all, replace "prohibit-password" with "no".
  • If you are going to allow root to log in but force them to use SSH keys, leave "prohibit-password" in place.

Save your changes and restart the SSH daemon:

sudo systemctl restart sshd

The Ultimate Step

Of course, if you don't need SSH running on your computer at all, make sure it is disabled.

sudo systemctl stop sshd

sudo systemctl disable sshd

If you don't open the window, no one can climb in.