A Step-by-step Guide For Securing 🔐 SSH Server
Almost every server 🖥 out there has SSH. Security issues 🔓 in your SSH server is a problem 🤦♂️ as it can let anyone get access to the server. This article is a step-by-step 📖 guide on securing SSH server by implementing better 🛠️ configuration, 🔑 public/private key authentication and 🎯 fail2ban.
To modify the behaviour of an SSH server we need to edit the
sshd_config file. On a typical Linux server the path to this config file is at:
Configuring SSH Server
As the first step to securing an SSH server, we'll modify some SSH server settings to harden security and performance. For each step, I've made a video showing you exactly what to do. Checkout the below video for more information 👇
1. Changing the listening port
SSH server by default 📢 listens at port 22, so scripts and botnets on the internet keep trying 🔨 to login through SSH using the default port. By changing the port to any random number between 10,000 👉 60,000 only specialized attacks 👨🏭 on the server will be possible. A good place to generate a random number is random.org.
Replace the red colored line(s) with the green one(s) 👇
2. Switch to
The newer SSH Protocol 2 supports public/private key algorithms better than RSA, along with lot of security holes 🕳 being fixed. So in this day and age one shouldn't be 🙅♂️ using the older protocol. To use Protocol version 2, add the below line to the configuration file 👇 I can simply start typing here 🤷♂️
Often times, servers have multiple networks adapters and IP addresses. By restricting 🚪 SSH to only the desired network adapter we reduce the risk 🚷 of getting unwanted login requests thus making SSH more secure. 👇 To restrict SSH to a particular network adapter 🔌.
4. Enable verbose logging
Verbose 🧐 logs are quite helpful for both the 👨💻 system administrator and
fail2ban. By enabling verbose logging we get a better idea 🤔 of what exactly is happening with the SSH server.
5. Restrict logins through SSH
On a typical 🐧 Linux environment, there will be more than two users in most cases. Telling SSH exactly which user is allowed to login is 👌 always better! As users like
backup are exploited to get into the server.
6. Prevent root login
In UNIX based operating systems,
root is an account which has complete control on the machine. If an attacker gets access to the
root account pretty much anything & everything is possible. NEVER ⚠️ LOGIN AS
root TO YOUR SERVER! For tasks that require elevated permissions, use
doas. To disable login access to the
root account, set
no, like so 👇
StrictModes is on
on by default, some Linux distributions may 🤷♂️ override it. When
StrictModes is turned on, the SSH server will only start if file permissions are ✅ properly setup. This prevents us from 🤦♂️ accidentally making permissions of config files and SSH keys too open and letting the attacker modify those. To ensure it is turned on, add
StrictModes on key to your configuration file or simply uncomment if already exists 👇
8. Reduce maximum retries
No matter how much prepared we are, there will always be script kiddies 😒 out there. To tackle those and prevent brute forcing we must drop the connection if the user fails to authenticate a set number of times. As you will read 😊 in the next stages we'll implement
fail2ban which is a more ⚔ robust solution for repeated login attempts.
9. Reject empty passwords
Although we will completely 🔒 disable password authentication later in this article, disabling empty passwords will make the 🕵️♀️ attacker hard to exploit those system accounts with no password. This setting is often applied as a 🦺 safety measure, just in case of a vulnerable account.
Most production servers don't have a 🖼 graphical user interface on them.
X11Forwarding allows us to run graphical applications on the server and have the interface forwarded to us. An attacker could 🤔 leverage this to exploit SSH, so when not using it's best to turn off.
11. Drop connections when inactive
It is really ⛔ fatal if SSH connections are left unclosed. Rogue SSH connections can be used by an attacker to gain access to the server. Also, in a situation where the system administrator opens a connection and physically 🚶♂️ leaves the computer, we don't want anyone to give arbitrary commands to our servers. To make the server disconnect automatically after 🕑 2 minutes of inactivity, set
ClientAliveInterval to 120 seconds 👇
- #ClientAliveInterval 0 + ClientAliveInterval 120
12. Disable SSH tunneling
Port forwarding ⏩ using SSH is referred to as "SSH Tunneling". An attacker can use it to hijack a port on the server to forward all it's packets to attacker's computer which can be quite harmful especially if it is 80 or 443 (these are HTTP and HTTPS ports used to serve websites). When not using, it's 👍 best to disable this.
Generating Secure SSH Keys
Now that we have a good base 👨🏭 to work with, the next step is to generate strong and secure SSH keys. Personally for ease of use I don't use a password along with SSH keys, but for added security you can optionally set a password which is safely ⛓ encrypted before transmitting.
The video is under production. Link will be updated as soon the video is released.
1. Checking OpenSSH version
The newer the OpenSSH version, the better and newer key algorithms it 🤩 supports. Click here to get a list of which algorithm is supported by what version of OpenSSH. Along with checking the version of OpenSSH installed on your workstation computer, it is required that the server also has the same version or newer. Run the below 👇 command to check your installed version of OpenSSH
ssh -V # OpenSSH_8.3p1, OpenSSL 1.1.1g 21 Apr 2020
2. Generating SSH Keys
DSA 🚨 is no longer considered safe these days, RSA ⚠️ is only safe with 4096 and above bit-length, ECDSA's 👁 security depends on your hardware. This leaves us with ED25519 🍏 which is supported by platforms like GitHub, GitLab and BitBucket and is the most recommended algorithm today.
Run the below command to generate an ED25519 key 👇
ssh-keygen -o -a 200 -t ed25519 -f ~/.ssh/ssh_key -C "$(whoami)@$(hostname)"
This ☝ should create two files named
ssh_key (which is your private key) and
ssh_key.pub which is the public key in your current directory.
3. Installing SSH Keys
Now that we have both the public and private keys on our workstation. We need to append the contents of public key into
~/.ssh/authorized_keys file on the server inorder to start using the generated SSH keys. This is as simple as running another command 👇
ssh-copy-id -p 21318 -i ~/.ssh/ssh_key.pub email@example.com
In the above command ☝ replace
firstname.lastname@example.org with your
ip address and the port number accordingly.
4. Disable Password Login
Completely 🚫 disabling password authentication will reduce the risk of getting brute forced. As without the exact private key that matches the public 🗝 key we installed on the server, authentication won't be successful.
fail2ban is a software that can read 📰 log files and add rules to the firewall. In this article we'll use
fail2ban to block repeated SSH authentication requests.
The video is under production. Link will be updated as soon the video is released.
sudo apt install fail2ban
Run the ☝ above command to install
fail2ban on a Debian/Ubuntu server. A jail is the configuration of
fail2ban for a service, and a filter is a file that tells
fail2ban exactly what lines to look for in the log files. On a typical installation of
jail.conf template is already given, we just need to copy that as
jail.local in the directory where
fail2ban in installed. To do that run 👇 the below command
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
fail2ban for SSH
As we now have the default
fail2ban config in place, it's time to configure
fail2ban for SSH. To get started open
/etc/fail2ban/jail.local in your favorite text editor and find the below snippet of config 👇
[sshd] # To use more aggressive sshd modes set filter parameter "mode" in jail.local: # normal (default), ddos, extra or aggressive (combines all). # See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details. #mode = normal port = ssh logpath = %(sshd_log)s backend = %(sshd_backend)s
And append the below property to enable the
ssh jail 👇
enabled = true
This will enable the SSH jail for
fail2ban. But we still have one more thing to do. By default
fail2ban's SSH filter won't look for key based authentication failures. As we have disabled password authentication we won't get passwords requests, but we'll get private key authentication failures. Modification of the SSH filter is required in this case.
To do that, open
/etc/fail2ban/filter.d/sshd.conf in your preffered text editor. In this file find the property named
cmnfailre. This property lists all patterns to look for in SSH's log file. Append the below pattern to this list to make
fail2ban block on private key authentication failure.
^%(__prefix_line)sConnection closed by authenticating user
.+ port \d+ \[preauth\]$
We have finished configuring SSH, generating SSH keys and installing
fail2ban and finally configuring
fail2ban to automatically block repeated attackers. As a final step, let's restart both SSH and
fail2ban services 👇
sudo systemctl restart sshd fail2ban