You are here: Home / Debian GNU/Linux / System / Security / Harden the SSH access security on Debian

Harden the SSH access security on Debian

by Pierre-Yves Landuré last modified Nov 11, 2017 10:44

The Secure SHell (aka. SSH) access is the main remote administration tool for a Unix server. By default, this access security is provided by the connection encryption and the need of login and password. This how-to propose various methods to harden a SSH server security.

This how-to is tested on:

  • Debian 6.0 Squeeze
  • Debian 7.0 Wheezy

Prerequisite

Make sure that the Secure SHell server is present:

command apt-get install openssh-server

Parameters

Provide the name of a standard user account to create if not already available on the server. To keep things simple, you can use the same login as the one you use on your personal computer:

STD_USER="myuser"

Prevent DDOS and brute-force attacks

Fail2ban is a tool monitoring SSH connexion failures, and blocking for a short time IP addresses that triggered 5 successive failures. This behaviour allow to prevent most of deny of service attacks and password stealing by brute-force attacks.

Install the software:

command apt-get install fail2ban

Enable fail2ban rules than apply to SSH connexions:

if [ ! -e '/etc/fail2ban/jail.local' ]; then
command touch '/etc/fail2ban/jail.local'
fi
if [ -z "$(command grep "\[ssh-ddos\]" '/etc/fail2ban/jail.local')" ]; then
echo "[ssh-ddos]
enabled = true

[pam-generic]
enabled = true
" >> '/etc/fail2ban/jail.local'
fi

Reload the tool configuration:

/etc/init.d/fail2ban restart

Disable root login

The "root" account is the first target of attacks. A good practice is to disable the possibility to log into the root account from SSH. The account is still available by using "su" and "sudo" tools.

Creation of a unprivileged account

Before disabling SSH root access, make sure a unprivileged account with a complex password is available. If you don't have such a account, you will not be able to log in your server through SSH.

Install a password generator software:

command apt-get install apg

Create a complex password to use with the new account:

command apg -q -m 12 -a  0 -n 1 -M NCLS

Create a unprivileged user account:

command adduser "${STD_USER}"

Create a .ssh folder for this user:

command mkdir --parents "/home/${STD_USER}/.ssh"
command chown "${STD_USER}":"${STD_USER}" "/home/${STD_USER}/.ssh"

Disable root login via SSH

Setup the SSH server to reject connections using root user:

command sed -i -e 's/PermitRootLogin.*/PermitRootLogin no/' '/etc/ssh/sshd_config'
/etc/init.d/ssh reload

Filter SSH users

In order to limit the number of user accounts available via SSH, it is possible to filter SSH users by group.

Create the group "ssh-users" containing users allowed to connect by SSH:

if [ -z "$(command grep "^ssh-users" '/etc/group')" ]; then
  command addgroup --system "ssh-users"
fi

Setup the SSH server to reject users that are not members of the group "ssh-users":

command echo '
# Limit access to users of group ssh-users
AllowGroups ssh-users' >> /etc/ssh/sshd_config

Reload the configuration:

/etc/init.d/ssh reload

Add users allowed to connect via SSH to the "ssh-users" group:

command adduser "${STD_USER}" ssh-users

Setting up a public key authentication

On the client computer

Create the unique certificate (private and public keys) identifying your user:

if [ ! -e "${HOME}/.ssh/id_rsa" ]; then
command ssh-keygen -t rsa -f "${HOME}/.ssh/id_rsa"
fi

Important: Save and protect with great care this files:

  • ${HOME}/.ssh/id_rsa
  • ${HOME}/.ssh/id_rsa.pub

Copy the user public key on the server (replace the bolded value by the server host name or IP address):

command ssh-copy-id -i "${HOME}/.ssh/id_rsa.pub" user@www.ssh-server.com

Note: if ssh-copy-id is not available on your system (Mac OS X), use:

command cat "${HOME}/.ssh/id_rsa.pub" \
| command ssh user@www.ssh-server.com 'umask 077;
test -d ~/.ssh || mkdir ~/.ssh ;
cat >> ~/.ssh/authorized_keys \
&& (test -x /sbin/restorecon \
&& /sbin/restorecon ~/.ssh ~/.ssh/authorized_keys >/dev/null 2>&1 \
|| true)'

On the server

Allow public key authentication:

command sed -i -e 's/^[#\t ]*PubkeyAuthentication[\t ]*.*$/PubkeyAuthentication yes/' \
'/etc/ssh/sshd_config'

Reload the configuration:

/etc/init.d/ssh reload

Note: It is possible to totally disable password authentication, but i don't recommend it. If you loose your private key, you won't be able to gain access to server by SSH.

Change the SSH server listening port

By default, the SSH server listen on port 22. Using another port than the default one limit the number of automated attacks.

On the server

Provide the custom port number (between 2048 and 65535):

SSH_PORT="16022"

Update the SSH server configuration:

command sed -i -e "s/^[#\t ]*Port[\t ]*.*\$/Port ${SSH_PORT}/" \
'/etc/ssh/sshd_config'

Reload the configuration:

/etc/init.d/ssh reload

Update fail2ban configuration:

echo "
# Custom SSH port
[ssh]
port = ${SSH_PORT}" >> '/etc/fail2ban/jail.local'

Restart fail2ban:

/etc/init.d/fail2ban restart

On the client computer

Provide the server host name:

SSH_HOST="www.ssh-server.com"

Provide the customized port number (between 2048 and 65535) used by the SSH server (see before):

SSH_PORT="16022"

Add a configuration section for the target server in SSH client configuration file:

if [ ! -e "${HOME}/.ssh/config" ]; then
touch "${HOME}/.ssh/config"
fi
if [ -z "$(command grep "${SSH_HOST}" "${HOME}/.ssh/config")" ]; then
echo "Host ${SSH_HOST}" >> "${HOME}/.ssh/config"
fi

Add the SSH server port in SSH client configuration file:

command sed -i -e "/${SSH_HOST}/a\\
Port ${SSH_PORT}" "${HOME}/.ssh/config"

Setting up Port Knocking

Le Port Knocking consiste à bloquer les connexions à un port (ici le port SSH) à moins qu'une séquence d'ouverture de connexion sur différents ports ne soit effectuée. Cette séquence correspond à "frapper à la porte" du serveur. C'est une méthode efficace pour masquer le port SSH d'un serveur aux visiteurs malveillants.

Port Knocking goal is to block connections to a port (in this case the SSH port) unless a sequence of connections on different ports is performed. This sequence corresponds to "knock" on the server. This is an effective method to hide the a server SSH port to malicious visitors.

On the server

Detect the SSH server port number:

SSH_PORT=$(command grep '^Port' '/etc/ssh/sshd_config' \
| command sed -e 's/^Port[\t ]*//g')

Provide the list of ports triggering the opening of SSH port:

SSH_KNOCK="9345,2193,37303"

If you want, you can use a list of random ports:

SSH_KNOCK="$((((${RANDOM} + ${RANDOM}) % 63488) + 2048)),$((((${RANDOM} + ${RANDOM}) % 63488) + 2048)),$((((${RANDOM} + ${RANDOM}) % 63488) + 2048))" 
echo "SSH_KNOCK='${SSH_KNOCK}'"

Install the knockd daemon:

command apt-get install knockd

Insert the opencloseSSH rule in knockd configuration. This rule open a SSH port for 10 seconds after a "knock":

command echo "
[opencloseSSH]
sequence      = ${SSH_KNOCK}
seq_timeout   = 5
tcpflags      = syn
start_command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport ${SSH_PORT} -j ACCEPT
cmd_timeout   = 10
stop_command  = /sbin/iptables -D INPUT -s %IP% -p tcp --dport ${SSH_PORT} -j ACCEPT
" >> '/etc/knockd.conf'

Remove the openSSH and closeSSH original rules:

command sed -i \
    -e '/\[openSSH\]/,/^[\t ]*$/{d}' \
    -e '/\[closeSSH\]/,/^[\t ]*$/{d}' \
  '/etc/knockd.conf'

Enable the daemon:

command sed -i \
-e 's/^START_KNOCKD=.*/START_KNOCKD=1/' \
'/etc/default/knockd'

Start the daemon:

/etc/init.d/knockd start

Setup a iptables rule rejecting by default new connections to the SSH port. The knockd rules selectively allow SSH access:

command echo "#"\!"/bin/bash
# Allow SSH access from domU
command iptables -C INPUT -p tcp -m state --state NEW --dport ${SSH_PORT} -j DROP > '/dev/null' \\
|| command iptables -A INPUT -p tcp -m state --state NEW --dport ${SSH_PORT} -j DROP" \
  > '/etc/network/if-up.d/iptables-ssh-reject'
command chmod +x '/etc/network/if-up.d/iptables-ssh-reject'

Load the rule:

/etc/network/if-up.d/iptables-ssh-reject

Important: To prevent problems, stay connected to your SSH session until you make sure to be able to open a new connection from the client computer.

On the client computer

Provide the server host name:

SSH_HOST="www.ssh-server.com"

Provide the knocking ports sequence needed to open the SSH port on the server:

SSH_KNOCK="9345,2193,37303"

Install knockd package (for the knock tool) and socket tool:

command apt-get install knockd socket

Add a configuration section for the target server in SSH client configuration file:

if [ ! -e "${HOME}/.ssh/config" ]; then
touch "${HOME}/.ssh/config"
fi
if [ -z "$(command grep "${SSH_HOST}" "${HOME}/.ssh/config")" ]; then
echo "Host ${SSH_HOST}" >> "${HOME}/.ssh/config"
fi

Setup the ProxyCommand option to use for knocking on the SSH server ports:

command sed -i -e "/${SSH_HOST}/a\\
TcpKeepAlive yes\\
ServerAliveInterval 150\\
ProxyCommand /bin/bash -c 'command knock %h $(echo ${SSH_KNOCK} | command tr ',' ' '); sleep 1; exec socket %h %p'" "${HOME}/.ssh/config"

Note: For Microsoft Windows clients, use KnockKnock.

References

These books can help you:

Thanks