Hardening SSH Server Setup
Commonly used for remote administration, transferring files, forwarding and encapsulating sensitive flows, OpenSSH has become a key element of a large number of IT systems.
Therefore, it is critical to control its configuration, harden its installation and apply strict hygiene rules for its operation. The recommendations presented in this note cover all these different aspects.
SSH, or Secure SHell, is an application layer protocol (layer 7 of the OSI model), which aims at correcting known deficiencies in
TELNET protocols, through 3 sub-protocols:
- SSH-USERAUTH, a client-side authentication protocol – RFC 4252;
- SSH-TRANS, a secure transfer protocol that allows server authentication and establishment of a secure communication channel (confidentiality and integrity) – RFC 4253;
- SSH-CONNECT, a connection protocol that allows communication channels multiplexing (data and commands) – RFC 4254.
- Presentation of OpenSSH
- Use cases
- Remote shell administration
- Best practices for using OpenSSH
- SSH Protocol
- Disable root access
- Created an unprivileged user account
- install a password generation tool
- Generate a complex password
- create a standard user account without privilege
- Create a .ssh folder for this user
- Disable root access
PrintLastLogdirective of sshd_config displays last connection details upon every user connection.
- Filter users with
- Create the
ssh-accesgroup containing the users who can connect using
- Add the users authorized to use
SSHaccess to the
- Configure the SSH server to refuse the connection of users who do not belong to this group
- So now reload the configuration
- Create the
- Protocol and network access
- ListenAddress and Ports
- Agent Forwarding
- Key Generation - sizes and algorithms
- Choosing Symmetric algorithms
- Regenerate Moduli
- Protect against DDOS and brute force attacks with fail2ban
- Installing fail2ban
- Configuring fail2ban
- Starting fail2ban
- Get the status
- Activate fail2ban rules for SSH connection on Debian stretch
- Test your SSH acces secuity
Presentation of OpenSSH
OpenSSH is developed and maintained by the OpenBSD project. It is, to date, the reference implementation of the SSH protocol found on a large number of systems, including servers (Unix, GNU/Linux, Windows), client machines and network devices. This software suite includes many tools:
- the server, sshd.
- several clients, depending of the purpose:
- remote shell connections: ssh;
- file transfers and downloads:
- a key generation tool,
- a keyring service,
- a utility for gathering the public SSH host keys of a number of hosts,
Remote shell administration
- SSH shall be used instead of historical protocols (
RLOGIN) for remote shell access.
RLOGINremote access servers shall be uninstalled from the system.
SFTPshall be used instead of historical protocols (
FTP) for file transfers.
- The implementation of
SSH tunnelsshall only be applied to protocols that do not provide robust security mechanisms and that can benefit from it (for example:
VNC, … ). This recommendation does not exempt from using additional low level security protocols, such as IPsec.
Best practices for using OpenSSH
SSH is standardized by a set of
RFC (4250-4254) specifying its communication protocols and the cryptographic mechanisms the protocol must support. SSH now exists in 2 versions:
SSHv1 has structural vulnerabilities that have been corrected in the next version. Version 1 of the protocol is now obsolete.
Only version 2 of the SSH protocol shall be authorized.
SSH is mainly a communication protocol. It is neither a Unix shell, nor a terminal, nor a command interpreter. OpenSSH is the most commonly encountered implementation of the SSH protocol. More than a protocol, it is a toolbox offering a large number of features.
OpenSSH, mandatory use of version 2 of the protocol is enforced by the following directive in
sudo sed -i -e 's/Protocol.*/Protocol 2/' '/etc/ssh/ssh_config' sudo /etc/init.d/ssh reload
Disable root access
root identifier is the first target of attacks. It is good practice to disable SSH login to the root account. Access to this account remains available via the
Created an unprivileged user account
SSH access to the
root account, make sure you have an alternative user account coupled with a sufficiently complex password. If you do not have a normal user account, your machine will no longer be accessible by
install a password generation tool
sudo apt install apg
Generate a complex password
sudo apg -q -m 12 -a 0 -n 1 -M NCLS
create a standard user account without privilege
sudo adduser <STD_USER>
Create a .ssh folder for this user
sudo mkdir --parents /home/<STD_USER>/.ssh sudo chown <STD_USER>:<STD_USER> /home/<STD_USER>/.ssh
Disable root access
root is an example of a generic account existing on all Unix/Linux systems, and used as an administrative account. The
root account shall not be remotely accessible:
Configure the SSH server to not accept connections with
sudo sed -i -e 's/PermitRootLogin.*/PermitRootLogin no/' '/etc/ssh/sshd_config' sudo /etc/init.d/ssh reload
PrintLastLog directive of sshd_config displays last connection details upon every user connection.
sudo sed -i -e 's/PrintLastLog.*/PrintLastLog yes/' '/etc/ssh/sshd_config' sudo /etc/init.d/ssh reload
Filter users with
In order to limit the number of accounts accessible directly via
SSH, it is possible to filter the users who can connect according to their group of membership.
ssh-acces group containing the users who can connect using
if [ -z "$(command grep "^ssh-acces" '/etc/group')" ]; then sudo addgroup --system "ssh-acces" fi
Adding group 'ssh-acces' (GID 120) ... Done.
Add the users authorized to use
SSH access to the
sudo adduser <STD_USER> ssh-acces
Adding user <STD_USER> to group 'ssh-acces' ... Adding user <STD_USER> to group ssh-acces Done.
Configure the SSH server to refuse the connection of users who do not belong to this group
echo ' # Limit access to users of group ssh-acces AllowGroups ssh-acces' >> /etc/ssh/sshd_config
So now reload the configuration
sudo /etc/init.d/ssh reload
Protocol and network access
ListenAddress and Ports
Administrative operations are commonly performed through SSH. As such, the SSH server should only be reachable from the administration network, which should ideally be separated physically from the operational network.
OpenSSH allows a user to forward flows through the server, both from the local network and the remote network. This feature can be used in rebound attacks to contact protected services (behind filtering gateways, listening on a different network. . . ). In addition, forwarding local flows may result in exposure of the internal network to uncontrolled flows.
Except for duly justified needs, any flow forwarding feature shall be turned off, in the SSH server configuration and in the local firewall by blocking connections.
Under OpenSSH, server side forwarding can be disabled using the AllowTcpForwarding directive of sshd_config:
sudo sed -i -e 's/AllowTcpForwarding.*/AllowTcpForwarding no/' '/etc/ssh/sshd_config' sudo /etc/init.d/ssh reload
Many Linux and BSD distros also ship with default configuration allowing X11 display forwarding. However, X11 is notoriously insecure by design, and rarely used over WAN connections.
X11Forwarding shall be deactivated by default. Exceptions to this recommendation should be carefully considered and security implications deeply analysed. As a general rule, installing an X server on a console-only host should be avoided, due to several security issues in the X Window System.
X11 forwarding shall be disabled on the server.
X11 forwarding can be done using the
X11Forwarding directive of
sudo sed -i -e 's/X11Forwarding.*/X11Forwarding no/' '/etc/ssh/sshd_config' sudo /etc/init.d/ssh reload
When X11 forwarding is active (remote execution of an
X11 client), compromise of the remote host can lead to uncontrolled information leakage:
- user keystrokes capture;
- display forwarding …
X11 redirection is required due to operational constraints, remote X11 clients should be treated with suspicion and their privileges shall be strictly limited.
ssh client should use the -X option and disable the ForwardX11Trusted option from its ssh_config configuration file: ForwardX11Trusted no
SSH agent forwarding is also still allowed by many SSH server configurations, and is still frequently used by SSH clients. However, this is insecure, as it allows anyone with root access on the server to intercept and manipulate all forwarded SSH connections.
The best practice is to disallow SSH agent forwarding with the following
sudo sed -i -e 's/AllowAgentForwarding.*/AllowAgentForwarding no/' '/etc/ssh/sshd_config' sudo /etc/init.d/ssh reload
Instead of using SSH agent forwarding, use the ProxyJump configuration directive in your SSH client configuration (or the -J flag on the SSH command line). Bogdan Popa has a succinct writeup about The Problem With SSH Agent Forwarding, and what to do instead.
There’s no equivalent to agent forwarding (or SSH proxying) with WireGuard. The safe alternative with WireGuard is to tunnel SSH traffic from client to jumphost through WireGuard, and allow the jumphost to forward SSH traffic to the destination SSH server.
SSH heavily relies on asymmetric cryptography for authentication. Failure to ensure the server authentication may result in numerous security impacts:
- risk of data theft through server impersonation (impossibility to verify the identity of the server);
- exposure to “man in the middle” attacks allowing to retrieve all data exchanged (keystrokes, displayed elements, logins, passwords, viewed or edited files. . . ).
The server authenticity shall always be checked prior to access. This is achieved through preliminary machine authentication by checking the server public key fingerprint, or by verifying the server certificate.
With OpenSSH, this control can be achieved by the client in different ways:
- ensure the SSH public key fingerprint of the server is the correct one (previously obtained by using
- add the SSH public key of the server in the known_hosts file manually;
- verify the signature the SSH certificate presented by the server with a trusted Certification Authority.
Explicit validation of the host key by the user can be specified using the
StrictHostKeyChecking attribute in
sudo sed -i -e 's/StrictHostKeyChecking.*/StrictHostKeyChecking ask/' '/etc/ssh/ssh_config' sudo /etc/init.d/ssh reload
OpenSSH applies, by default, a Trust On First Use (TOFU) security model: during the first connection, if the client cannot authenticate the remote host, ssh requests the user to verify the server key fingerprint. If the user validates the fingerprint, ssh registers the key into the known_hosts file to allow automatic validation for the following connections.
Key Generation - sizes and algorithms
SSH can handle several cryptographic algorithms and key sizes. Some of them do not meet the security requirements. In practice, the SSH “host” keys (used to authenticate an SSH server) are rarely renewed. It is, therefore, important to choose a key long enough from the beginning. The DSA implementation in OpenSSH supp;orts key up to 1024 bits long. Such keys are now considered insecure and their use is strongly discouraged. You can also choose to disable support for RSA keys The Elliptic curve algorithms must be chose as cryptographic algorithms. Ed25519 algorithm, which is considered state of the art. Elliptic curve algorithms in general are sleek and efficient and unlike the other well known elliptic curve algorithm ECDSA, this Ed25519 does not depend on any suspicious NIST defined constants
ECDSA keys should be favoured over RSA keys when supported by SSH clients and servers.
Key quality is an important robustness factor, directly linked to the RNG (Random Number Generator) used during the genera- tion process. Providing a proper RNG is thus essential. Several equipments and computers, including basic embedded components or virtual machines lack such a proper generator. Keys should be generated in a context where the RNG is reliable, or at least in an environment where enough entropy has been accumulated. This recommendation is all the more important since it is common to generate the sshd host keys by script upon first service startup. A mechanism aimed at changing the generated keys shall be proposed and initial keys shall be replaced.
- So, in your server, in
/etc/ssh/sshd_configfile comment or delet HostKey
// file: "/etc/ssh/sshd_config" #HostKey /etc/ssh/ssh_host_dsa_key #HostKey /etc/ssh/ssh_host_rsa_key
- Always in
/etc/ssh/sshd_configadd HostKey attribute for ED25519
// file: "/etc/ssh/sshd_config" HostKey /etc/ssh/ssh_host_ed25519_key
- And delete
sudo rm -v /etc/ssh/ssh_host_dsa_key* sudo rm -v /etc/ssh/ssh_host_rsa_key*
- Generate an
sudo ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key
Generating public/private ed25519 key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /Users/<user id>/.ssh/id_ed25519. Your public key has been saved in /Users/<user id>/.ssh/id_ed25519.pub. The key fingerprint is: SHA256:H6/ZSrfIs42k0QjA2RMUZlfldBHrneC3q+QZjjiO+bU <user id>@<host>.local The key's randomart image is: +--[ED25519 256]--+ | .*.....o +o | | . = o o . . | | + o ... | | . . .....| | . S . ..o.| | . + o . .| | o *.oo . | | oBoO*.o .| | o+=@Eo=.. | +----[SHA256]-----+
- You do not need to enter a passphrase, but it’s highly recommended as it protects your private key if compromised. If so, someone would still need your passphrase in order to unlock it. The exception to this is if you’re running an automated process such as as cron job. You should then leave the password out. From ssh.com: “Generally all keys used for interactive access should have a passphrase. Keys without a passphrase are useful for fully automated processes.”
- ED25519 keys should be favoured over ECDSA keys when supported by SSH clients and servers. The Ed25519 algorithm, which is considered state of the art. Elliptic curve algorithms in general are sleek and efficient and unlike the other well known elliptic curve algorithm ECDSA.
- An host authentication private key shall only be readable by the
sshdservice. Under Unix/Linux, only root is granted such a privilege :
sudo chmod 600 /etc/ssh/ssh_host_ed25519_key
sudo systemctl restart sshd
Some rules can ensure that the entropy pool is properly filled:
- keys must be generated on a physical equipment;
- system must have several independent sources of entropy;
- key generation shall occur only after a long period of activity (several minutes or even hours)
Choosing Symmetric algorithms
Once the peers are mutually authenticated, the communication channel is protected in confidentiality and in integrity.
The encryption algorithm shall either be
AES256-CTR. And the integrity mechanism shall rely on
The cryptographic algorithms are negociated between the client and the server, so the list of available algorithms must be set on both sides. Weak algorithms shall be removed from the negotiated cryptographic suites.
CBC mode implemented in OpenSSH has known vulnerabilities, CTR mode is thus recommended. Integrity algorithms
HMAC-SHA512are recommended, are sup-ported since OpenSSH version 5.9.
Under OpenSSH, the following directives shall be added in
/etc/ssh/ssh_config configuration files:
KexAlgorithms email@example.com Ciphers aes256-ctr,aes192-ctr MACs firstname.lastname@example.org,email@example.com
/etc/ssh/moduli file contains prime numbers and generators used by the SSH server for the Diffie-Hellman key exchange. Your default
/etc/ssh/moduli is probably not unique. Generating a new file may harden your server.
cd /tmp/ sudo ssh-keygen -G moduli-2048.candidates -b 2048 sudo ssh-keygen -T moduli-2048 -f moduli-2048.candidates sudo cp /tmp/moduli-2048 /etc/ssh/moduli sudo rm /tmp/moduli-2048
Generating these file might take awhile.
Protect against DDOS and brute force attacks with fail2ban
Fail2ban scans log files (e.g.
/var/log/auth.log and bans IPs that show the malicious signs – too many password failures, seeking for exploits, etc. Generally Fail2Ban is then used to update firewall rules to reject the IP addresses for a specified amount of time, although any arbitrary other action (e.g. sending an email) could also be configured. Out of the box Fail2Ban comes with filters for various services (apache, courier, ssh, etc).
fail2ban can be installed using apt:
sudo apt install fail2ban
Requirements Python version 2.6 or higher
The config file is
/etc/fail2ban/jail.conf The Default section contains the general information about the bans.
Once you have installed and configured fail2ban the way you want, you just need to start it:
sudo systemctl restart fail2ban
sudo systemctl stop fail2ban; sudo systemctl start fail2ban
Get the status
sudo fail2ban-client status
and see the
/var/log/fail2ban.log log file
tail -f /var/log/fail2ban.log
Activate fail2ban rules for SSH connection on Debian stretch
if [ ! -e '/etc/fail2ban/jail.d/defaults-debian.conf' ]; then sudo touch '/etc/fail2ban/jail.d/defaults-debian.conf' fi if [ -z "$(command grep "\[DEFAULT]" '/etc/fail2ban/jail.d/defaults-debian.conf')" ]; then sudo echo "[DEFAULT] destemail = root sender = fail2ban # Ignore localhost & private IP ignoreip = 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 " >> '/etc/fail2ban/jail.d/defaults-debian.conf' fi if [ -z "$(command grep "\[sshd]" '/etc/fail2ban/jail.d/defaults-debian.conf')" ]; then sudo echo "[sshd] enabled = true maxretry = 3 findtime = 120 bantime = 1200 " >> '/etc/fail2ban/jail.d/defaults-debian.conf' fi
And now reload the config with :
sudo systemctl restart fail2ban
maxretryv: Number of matches (i.e. value of the counter) which triggers ban action on the IP.
findtime: The counter is set to zero if no match is found within “findtime” seconds.
bantime: Duration (in seconds) for IP to be banned for. Negative number for “permanent” ban.
ignoreip: can be an IP address, a CIDR mask or a DNS host. Fail2ban will not ban a host which matches an address in this list. Several addresses can be defined using space separator.
Test your SSH acces secuity
- with sshcheck
- with CryptCheck
with SSHScan (Requirement Python version 2.6 or higher)
cd /tmp/ wget https://raw.githubusercontent.com/arthepsy/ssh-audit/master/ssh-audit.py chmod +x /tmp/ssh-audit.py ./ssh-audit.py localhost
All GREEN, so everthing is good !